React createPortal 不会在没有任何错误的情况下向 DOM 添加元素

问题描述 投票:0回答:1

我正在尝试使用 React 和 MaterialUI 创建动态模式。

目前添加它们是这样的:

// Confirm.js
import { WarningAmber } from '@mui/icons-material'
import { LoadingButton } from '@mui/lab'
import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from '@mui/material'
import { t } from 'i18next'
import { useState } from 'react'

export default function Confirm({ open, setOpen, title, message, onConfirm, onCancel = () => null }) {
  const [saving, setSaving] = useState(false)

  function handleCancel() {
    onCancel()
    setOpen(false)
  }

  function handleConfirm() {
    setSaving(true)
    onConfirm()
    setSaving(false)
    setOpen(false)
  }

  return (
    <Dialog onClose={() => setOpen(false)} open={open}>
      <DialogTitle className="flex items-center">
        <WarningAmber className="mr-2" />
        {title}
      </DialogTitle>
      <DialogContent>
        <DialogContentText>{message}</DialogContentText>
      </DialogContent>
      <DialogActions>
        <Button className="mx-2" variant="text" onClick={handleCancel}>
          {t('cancel')}
        </Button>
        <LoadingButton loading={saving} variant="contained" onClick={handleConfirm}>
          {t('yes')}
        </LoadingButton>
      </DialogActions>
    </Dialog>
  )
}
// in any component
export default function SomeTable() {
const [confirmDelete, setConfirmDelete] = useState(false)
const [something, setSomething] = useState(null)

// triggered by a button on table
function handleDelete(item) {
setConfirmDelete(true)
setSomething(item)
}
async function deleteSomething() {
// delete
}

return (
<>
{*
table
*}

  <Confirm
    open={confirmDelete}
    setOpen={setConfirmDelete}
    title="are-you-sure"
    message="delete-confirm-message"
    onConfirm={deleteSomething}
  />
</>
);
}

我不想像这样将“确认”组件添加到所有其他组件中。

相反,我想要这个:

// useDialog.js
import { useState } from "react";
import { createPortal } from "react-dom";
import Confirm from "../components/common/Confirm";

export default function useConfirm() {
  const [open, setOpen] = useState(true);

  return {
    confirm: ({ title, message, onConfirm, onCancel = () => null }) =>
      createPortal(
        <Confirm
          open={open}
          setOpen={setOpen}
          title={title}
          message={message}
          onConfirm={onConfirm}
          onCancel={onCancel}
        />,
        document.getElementById("root")
      )
  };
}
// any component
import useConfirm from "./hooks/useConfirm";
import "./styles.css";
import { Button } from "@mui/material";

export default function App() {
  const { confirm } = useConfirm();
  return (
    <div className="App">
      <Button
        onClick={() =>
          confirm({
            title: "Modal Title",
            message: "Modal Message",
            onConfirm: () => null
          })
        }
      >
        Open Confirm Modal
      </Button>
    </div>
  );
}

但是当我这样做时,createPortal 没有做任何事情,也没有抛出任何错误。 这是沙箱https://codesandbox.io/s/modest-saha-hjvgwz?file=/src/App.js

reactjs material-ui react-dom react-portal
1个回答
0
投票

请使用以下代码更新您的

useDialog.js
文件。我希望它会起作用。

import { useState } from "react";
import * as ReactDOM from 'react-dom';
import { createPortal } from "react-dom";
import Confirm from "../components/common/Confirm";

export default function useConfirm() {
  const [open, setOpen] = useState(true);
  const root = ReactDOM.createRoot(document.getElementById("root"));

  return {
    confirm: ({ title, message, onConfirm, onCancel = () => null}) =>
      {
        return (
          root.render(createPortal(
            <Confirm
              open={open}
              setOpen={setOpen}
              title={title}
              message={message}
              onConfirm={onConfirm}
              onCancel={onCancel}
            />,
            document.getElementById("root")
          ), document.createElement("div"))
        )
      }
  };
}
© www.soinside.com 2019 - 2024. All rights reserved.