使用React高阶组件+createPortal写一个Modal吧

效果展示

使用React高阶组件+createPortal写一个Modal吧_第1张图片
modal.gif

Portal

Portals 提供了一种很好的将子节点渲染到父组件以外的 DOM 节点的方式。

ReactDOM.createPortal(child, container)

第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或碎片。第二个参数(container)则是一个 DOM 元素。

实践

自己写的一个实践,实现弹出modal,利用createPortal,以及高阶组件,如有不妥,请多提意见,谢谢!

高阶组件需要抽象出什么?

思考一个弹出窗口需要具备什么

  • 需要外部提供props.visible来确定 隐藏/显示
  • 需要在body下创建dom节点并将Portal插入到里面
  • 需要在Protal.componentWillUnmount时删除创建的dom节点
  • 需要外部提供props.hide、props.show 两个方法
  • 需要将props传递给子组件
  • 点击背景可以隐藏

Do It

高阶组件Portal

import React,{ Component } from 'react';
import ReactDOM from  'react-dom';
import './Portal.css';


export default function Portal(WrappedComponent) {
    return class extends Component{
        constructor(props){
            super(props);
            //直接插入dom节点到body下
            if(!this.node){
                this.node = document.createElement("div");

                document.body.appendChild(this.node);
            }
        }
        //组件即将卸载时候删除dom节点
        componentWillUnmount(){
            this.node && this.node.remove();

        }
        //渲染内容
        renderContent(){
            return (
                
{/*给WrappedComponent传递props*/}
) } render(){ const { visible} = this.props; //visible控制显示/隐藏 if(visible) return ( this.node && ReactDOM.createPortal(this.renderContent(),this.node) ) else return null; } } }

Modal

思考我们需要什么功能?
  • 可以自ok按钮和cancel按钮,执行props.ok/props.cancel
  • 可以props.title 定义标题
  • 标题最右边有关闭按钮
  • 有内容渲染 且与Modal无关
  • 支持自定义的className 和 style,props传递

思考后可以写出如下代码

import React,{ Component } from 'react';
import Portal from './Portal'
import './Modal.css';

class Modal extends  Component{
    onOK = ()=>{
        this.props.onOK();
        this.props.hide();
    };
    onCancel = ()=>{
        this.props.onCancel();
        this.props.hide();
    };

    render(){
        const {hide,visible,style,className,title,onOK,onCancel} = this.props;
        //合并style
        let newStyle = Object.assign({},style,{
            display:visible?"block":"false",
        });
        return (
            

{title} 关闭

{this.props.children && this.props.children}
{/*不显示没有对应方法的按钮*/} {onCancel?取消:null} {onOK?确定:null}
) } } //注意使用高阶组件进行装饰 export default Portal(Modal)

APP.js调用

class App extends Component {
 
    state={
        visible:false,
        hello:"hello world"
    };

    hide = ()=>{
        this.setState({
            visible:false
        })
    };
    ok = ()=>{
      console.log("ojbk")
    };
    cancel = ()=>{
        console.log("cancel")
    };
    toggleVis = ()=>{
        this.setState({
            visible:!this.state.visible
        })
    };
  render() {
    return (
      
{/*{this.state.show?:""}*/} {/**/}

快乐每一天

我是小白

); } } export default App;

至此,我们有了一个可以高度扩展的Modal啦,你更可以基于Portal的装饰,写绝大多数的在页面弹出的东东,发挥你的创造力吧

推一下自己基于React全家桶写的音乐WebAPP
大佬给个星呗~https://github.com/Volankey/React-Music

你可能感兴趣的:(使用React高阶组件+createPortal写一个Modal吧)