如何在 React 中创建可重用的自定义模态组件?

IT技术 reactjs ajax modal-dialog
2021-03-28 07:06:55

我对 React 中的模态概念有疑问。当使用带有 jQ​​uery 的服务器端呈现模板时,我习惯于有一个始终可用的空全局模态模板(包含在始终扩展的基本模板中)。然后在进行 AJAX 调用时,我只是填充了模态……像这样:

$('.modal-global-content').html(content);
$('.modal-global').show();

那么我如何在 React 中实现这个概念呢?

2个回答

有几种方法可以做到这一点。第一个涉及从父组件传入模态状态。以下是如何执行此操作 - 首先使用父App.js组件:

// App.js

import React from "react";

import Modal from "./Modal";

const App = () => {
  const [showModal, updateShowModal] = React.useState(false);

  const toggleModal = () => updateShowModal(state => !state);

  return (
    <div>
      <h1>Not a modal</h1>
      <button onClick={toggleModal}>Show Modal</button>
      <Modal canShow={showModal} updateModalState={toggleModal} />
    </div>
  );
}

export default App;

Modal.js是将呈现模态子组件:

// Modal.js

import React from "react";

const modalStyles = {
  position: "fixed",
  top: 0,
  left: 0,
  width: "100vw",
  height: "100vh",
  background: "blue"
};

const Modal = ({ canShow, updateModalState }) => {
  if (canShow) {
    return (
      <div style={modalStyles}>
        <h1>I'm a Modal!</h1>
        <button onClick={updateModalState}>Hide Me</button>
      </div>
    );
  }

  return null;
};

export default Modal;

这种方式非常好,但如果您在整个应用程序的许多地方重复使用模态,它可能会有点重复。因此,我建议使用上下文 API。

为你的模态状态定义一个上下文对象,在你的应用程序顶部附近创建一个提供者,然后每当你有一个需要渲染模态的子组件时,你就可以渲染模态上下文的使用者。通过这种方式,您可以轻松地在组件树中更深地嵌套您的模态,而无需一直向下传递回调。以下是如何执行此操作 - 首先创建一个context.js文件:

// context.js

import React from "react";

export const ModalContext = React.createContext();

现在更新的App.js文件:

// App.js

import React from "react";

import { ModalContext } from "./context";
import Modal from "./Modal";

const App = () => {
  const [showModal, updateShowModal] = React.useState(false);

  const toggleModal = () => updateShowModal(state => !state);

  return (
    <ModalContext.Provider value={{ showModal, toggleModal }}>
      <div>
        <h1>Not a modal</h1>
        <button onClick={toggleModal}>Show Modal</button>
        <Modal canShow={showModal} updateModalState={toggleModal} />
      </div>
    </ModalContext.Provider>
  );
}

export default App;

最后是更新的Modal.js文件:

// Modal.js

import React from "react";

import { ModalContext } from "./context";

const modalStyles = {
  position: "fixed",
  top: 0,
  left: 0,
  width: "100vw",
  height: "100vh",
  background: "blue"
};

const Modal = () => {
  return (
    <ModalContext.Consumer>
      {context => {
        if (context.showModal) {
          return (
            <div style={modalStyles}>
              <h1>I'm a Modal!</h1>
              <button onClick={context.toggleModal}>Hide Me</button>
            </div>
          );
        }

        return null;
      }}
    </ModalContext.Consumer>
  );
};

export default Modal;

这是使用上下文的工作版本Codesandbox链接。我希望这有帮助!

@elcarcharias 我认为最好的方法是将产品的想法作为currentProductId. 然后,在您的Modal组件中,您可以使用useEffectGET 请求,传入context.currentProductId. GET 请求将返回产品详细信息。您现在可以将这些细节保存在Modal组件的本地状态中,并根据需要渲染它们
2021-05-29 07:06:55
感谢使用上下文对我来说是全新的。我有一个可能很愚蠢的问题,在名为 Catalog 的组件中,我过滤了产品,在 rpodcut 的 Edit 中,我想在此模式中渲染一个组件 ProductEdit 我如何在 axios.get 方法中调用它?
2021-06-19 07:06:55

您可以通过使用 css 和 JSX 来解决此问题的一种方法。

这是应用程序,我可以有任何东西,比如一个按钮,一个链接,任何东西让我们假设我们有一个链接(react-router-dom),可以将我们重定向到DeletePage

删除页面呈现一个Modal 你将提供的titleactions模态的作为props

const App = () => {
  return(
    <Link to="/something/someid">SomeAction</Link>
  )
}

const DeletePage = () => {
  return(
    <Modal
      title="Are you sure you want to delete this"
      dismiss={() => history.replace("/")}
      action={() => console.log("deleted") }
      />
  )
}

模态

const Modal = (props) => {
  return(
      <div>
        <div className="background" onClick={props.dismiss}/>
        <h1>{props.title}</h1>
        <button onClick={props.dismiss}>Cancel</button>
        <button onClick={props.action}>Delete</button>
      </div>
    )
}
  • z-index模态的设置为高数
  • position: fixed 模态组件的
  • 当用户单击背景时,模型将消失(实现这一点的方法有很多,例如模态状态、重定向等,我已将重定向作为其中一种方法)
  • cancel button 也有相同的 onClick 功能,即解除
  • Delete buttonaction通过 props 传递函数

由于 css,这个方法有一个缺陷,因为如果你的父组件有一个 position 属性,relative那么这将中断。
无论 z-index 有多高,模态都将保留在父级内


为了拯救我们,React-Portal 出现了


React 门户以自己的方式创建了一个“门户”
您可能拥有的React 代码将在内部呈现DOMid 为#root(在大多数情况下)

因此为了呈现我们Modal的最顶层,我们在公共文件中 创建另一个
DOM element例如<div id="modal"></div>index.html

所述Modalreact组件代码将略有改变


const Modal = (props) => {
  return ReactDOM.createPortal(
      <div>
        <div className="background" onClick={props.dismiss}/>
        <h1>{props.title}</h1>
        <button onClick={props.dismiss}>Cancel</button>
        <button onClick={props.action}>Delete</button>
      </div>
    ),document.querySelector("#modal")
}

休息都是一样的

@elcarcharias 进行调用componentDidMount并根据响应呈现Modal并传递组件为props
2021-05-25 07:06:55
谢谢,但是如果我想在 modal 中显示另一个组件,我可以将它作为它的 prop 传递给 Modal 组件吗?
2021-05-31 07:06:55
但是如果我想在ajax调用中将此组件传递给模态道具?
2021-06-08 07:06:55
@elcarcharias 是的,绝对是 return <div>{props.anotherComponent}</div>
2021-06-09 07:06:55