在 React 中构建模态组件而不将其嵌套在调用者组件中

IT技术 javascript reactjs react-redux modal-dialog
2021-05-14 12:20:42

我正在尝试从非相关组件调用模态(不使用任何父子关系)。

为了做到这一点,我正在尝试使用 React Redux(这是我见过的可以在两个不相关组件之间建立连接的唯一方法)。CodeSandbox 上的一个示例显示了我正在尝试做的最低限度的工作。

我的问题是我不想包含<Modal><Button>渲染函数中。我希望能够简单地翻转标志Button.js<Modal>出现。据我所知,这应该是 Redux 的优势之一。

它可能看起来不重要,但除了我知道这是可以完成的事情的事实之外,所以我想知道如何做,如果我将其包含<Modal>在组件的渲染中,它将在另一段代码中对我有用函数它将多次渲染模态(我在列表中渲染该组件)。

编辑:

为了清楚起见(根据 CodeSandbox 上的示例),我使用的是 React 类而不是函数式组件;所以没有钩子useDispatch,而是像函数一样mapDispatchToProps是我想要的方式。

1个回答

我会推荐使用 React Portal,这会将它注入给定节点,我发现它是创建模态的最佳解决方案。我在dailylivedeals.com 中将其用作POC

import ReactDOM from "react-dom";

render() { 
    return ReactDOM.createPortal(
    this.props.children,
    Document.body
  );
}

这是使用 React 自身特性的最简单和最干净的方法。

优势:

  1. 更干净更简单
  2. 每个模态实例都可以有自己的模态
  3. 可以打开多个模态(甚至从模态内部)
  4. 模态目标可以是动态的(如模态内的模态)
  5. 可以使用代码轻松控制多个模态。

更新 :

模态代码

import React, {useEffect, useState} from "react";
import ReactDOM from "react-dom";
import {Link} from 'react-router-dom';

import "./modal.scss";

let Modal = ({visible, id, hideModal, children, ...props}) => {

    let [show, setShow] = useState(false);

    useEffect(() => {
        setShow(visible);
        console.log(visible);
    }, [visible]);

    let toggleVisibility = () => {
        //hideModal();
        setShow(!show);
    }

    useEffect(() => {
        if (!show) {
            hideModal();
        }
    }, [show]);


    return <div className="modal-scratchpad">
        {show ?
            ReactDOM.createPortal(
                <div id={`${id}-modal-wrapper`} className="sample-modal-wrapper">
                    <div id={`${id}-modal-backdrop`} className="sample-modal-backdrop">
                    </div>
                    <div id={`${id}-modal-container`} className="sample-modal-container">
                        <div id={`${id}-modal`} className="sample-modal">
                            {children}
                            <div onClick={toggleVisibility} className="sample-modal-cross-button">{'\u2716'}</div>
                        </div>
                        <style type="text/css">
                            {"body {" +
                            "overflow:hidden" +
                            "}"}
                        </style>
                    </div>
                </div>
                , document.body)
            : <></>
        }
    </div>

};

export default Modal;