React实现优雅的弹窗

本文介绍了在React中实现弹窗的两种方法,一种是通过传统DOM操作,另一种是利用React的Portal组件。讨论了unstable_renderSubtreeIntoContainer的缺点并详细展示了如何使用Portal创建静态和动态弹窗。动态弹窗涉及到ReactDOM的render和unmountComponentAtNode方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        实现弹窗的原理关键在于,如何将弹窗组件挂载到任意的dom上,参考weui.js,提供了思路,可以通过append将元素添加到指定的父节点上,来实现弹窗的显示,隐藏的时候在移除该元素即可,如下示例:

参考:https://github.com/Tencent/weui.js/blob/master/src/picker/picker.js

        在react同样可以使用该思路来实现,弹窗的显示和隐藏。但是在react中一般不这么搞,因为react已经提供了相关的API来实现,分别是unstable_renderSubtreeIntoContainer和Portal组件,其中unstable_renderSubtreeIntoContainer已经过去,被Portal替代,原因是unstable_renderSubtreeIntoContainer使用起来麻烦,而且换不稳定,主要表现在以下两点:

1、需要自己管理组件的生命周期,用React.render()渲染到某个DOM节点,如果要卸载的话需要手动执行unmountComponentAtNode()

2、接受不到Context的值。用render()渲染的组件是无法获取到上级节点的Context值的。比如多语言机制实现。

        下面主要介绍Portals的两种弹窗的用法:

一、静态弹窗

        静态弹窗是初始化渲染的时候要加载的内容已经被渲染到指定的节点里面,隐藏和显示通过变量控制。

1、dialog

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

export default function Dialog(props) {
    const [node, setNode] = useState();

    useEffect(() => {
        const element = document.createElement('div');
        document.body.appendChild(element);
        setNode(element);
        return () => {
            document.body.removeChild(element);
        };
    }, []);

    return node ? ReactDOM.createPortal(props.children, node) : null;
}

2、App

import React, {useState} from 'react'
import Dialog from "./dialog";

export default function App() {
    const [show, isShow] = useState(false)
    return (
        <div>
            <button onClick={() => {
                isShow(show=> !show)
            }}>点击显示
            </button>
            {show && <Dialog>
                <div>
                    我是一个简答的弹窗
                </div>
            </Dialog>}
        </div>
    );
}

二、动态弹窗

        动态弹窗是初始化渲染的时候要加载的内容没有被渲染到指定的节点里面,需要显示的时候再加载,隐藏和显示单独控制。

1、dialog同上

2、App

import React from 'react'
import ReactDOM from 'react-dom'
import Dialog from "./dialog";

export default function App() {
    const div = document.createElement('div');
    return (
        <div>
            <button onClick={() => {
                ReactDOM.render(
                    <Dialog>
                        我是一个弹窗
                    </Dialog>,
                    div
                );
            }}>点击显示
            </button>
            <button onClick={() => {
                const unmountResult = ReactDOM.unmountComponentAtNode(div);
                if (unmountResult && div.parentNode) {
                    div.parentNode.removeChild(div);
                }
            }}>点击隐藏
            </button>
        </div>
    );
}

三、效果图

 参考文档:

https://zhuanlan.zhihu.com/p/52016989

https://react.docschina.org/docs/portals.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值