用自定义hooks优雅的解决弹窗状态问题

315 阅读1分钟

痛点:

  • 当我们在项目里面使用弹窗的时候,不可避免的会需要额外的存储一些状态,比如visible变量
  • 在table操作列的时候打开弹窗有时候,需要将当前行的数据传送到弹窗里面,这时候,你不得不将当前行数据存储到state里面。
  • 其它需要存储状态的情况

往期解决方案 ,但是在使用的过程中,前面的方案发现了一个比较严重缺陷,就是拿不到context,因为是自己单独调用的render方法渲染的。另外一个原因现在大家版本都是react 18+ 以上,已经不推荐使用render这种方式去渲染,所以用自定义hooks的方式优化了一版本。

用法

useDialog

import React, { cloneElement, useCallback } from 'react';

export interface UserDialogProps {
  closeDialog: () => void;
  visible: boolean;
  setVisible: React.Dispatch<React.SetStateAction<boolean>>;
}

export const useDialog = <T,>(Component) => {
  const [visible, setVisible] = React.useState<boolean>(false);
  const detailRef = React.useRef<any>({});
  const open = useCallback((detail: T) => {
    detailRef.current = detail;
    setVisible(true);
  }, []);
  const closeDialog = () => {
    setVisible(false);
  };
  const node = cloneElement(<Component />, {
    visible,
    setVisible,
    closeDialog,
    ...detailRef.current,
  });
  const holder = React.useMemo(() => {
    if (visible) {
      return node;
    }
    return null;
  }, [visible]);
  return { open, closeDialog, holder };
};

useDialog会往传进来的组件props里面注入三个固定参数:

  • visible 弹窗的显隐变量
  • closeDialog 关闭弹窗
  • setVisible (通常不需要)

Modal组件

import {Modal} from 'antd';
import {UserDialogProps} from './useDialog';
export interface IModalProps extends UserDialogProps {
    
}
const Modal = (props) => {
    const {visible, closeDialog} = props;
    return <Modal
        visible={visible}
        onCancel={closeDialog}
    >
        <p>123</p>
       </Modal>
}
export default Modal;

父组件

import React from 'react';
import {Button} from 'antd';
import Modal, {IModalProps} from './Modal';
import {useDialog} from './useDialog';
const App = () => {
    const {open, holder} = useDialog<IModalProps>(Modal)
    const handleClick = () => {
        open({
           // ... 传给Modal的props参数
        })
    }
    return <div>
        {holder}
        <Button onClick={handleClick}></Button>
    </div>
}

总结

优化的这一版目前还没有发现什么问题,对比之前render方案带来的副作用,已经全部修复了。