【问题标题】:Material UI Dialog turned to Hook flickeringMaterial UI Dialog 转为 Hook 闪烁
【发布时间】:2020-10-03 09:04:36
【问题描述】:

我正在尝试将 Material UI 的对话框变成一个“useDialog”钩子,以便跟踪它自己的打开状态。

不幸的是,我遇到了一个问题,即每当我在层次结构中更新状态时,对话框就会闪烁,我不确定为什么以及如何规避它。我觉得某处需要 useRef ,但我不确定。这是一个复制的最小示例:https://codesandbox.io/s/flickering-dialog-minimal-example-ehruf?file=/src/App.js

以及有问题的代码:

    import React, { useState } from "react";
    import {
      Button,
      Dialog,
      DialogActions,
      DialogContent,
      DialogTitle
    } from "@material-ui/core";

    export default function App() {
      const [openDialog, Dialog] = useDialog();
      const [counter, setCounter] = useState(0);

      return (
        <div>
          <Dialog title="Hello">
            <div>{counter}</div>
            <button onClick={() => setCounter(counter => counter + 1)}>
              Increase
            </button>
          </Dialog>
          <button onClick={openDialog}>Open dialog</button>
        </div>
      );
    }

    const useDialog = () => {
      const [open, setOpen] = useState(false);
      const handleClose = () => {
        setOpen(false);
      };

      const someDialog = ({ title, children }) => {
        return (
          <Dialog open={open} onClose={handleClose}>
            <DialogTitle>{title}</DialogTitle>
            <DialogContent>{children}</DialogContent>
            <DialogActions>
              <Button onClick={handleClose} color="primary">
                Close
              </Button>
            </DialogActions>
          </Dialog>
        );
      };
      return [
        () => {
          setOpen(true);
        },
        someDialog
      ];
    };

【问题讨论】:

    标签: reactjs material-ui react-hooks


    【解决方案1】:

    对话框闪烁的原因是App 中的每个渲染(由于状态更改)都会创建一个新的对话框组件。旧的Dialog 被卸载并替换为新的Dialog

    一个经验法则是你永远不应该在渲染时定义组件。

    这就是为什么我建议您将自定义对话框组件与 useDialog 钩子分开:

    const MyDialog = ({ open, handleClose, title, children }) => {
      return (
        <Dialog open={open} onClose={handleClose}>
          <DialogTitle>{title}</DialogTitle>
          <DialogContent>{children}</DialogContent>
          <DialogActions>
            <Button onClick={handleClose} color="primary">
              Close
            </Button>
          </DialogActions>
        </Dialog>
      );
    };
    

    但是,您可以将一些逻辑保留在 useDialog 中并重用它们:

    const useDialog = () => {
      const [open, setOpen] = useState(false);
      const openDialog = () => {
        setOpen(true);
      };
      const handleClose = () => {
        setOpen(false);
      };
      const props = {
        open,
        handleClose
      };
      return [openDialog, props];
    };
    

    更多关于why returning components from hook can be a bad idea

    【讨论】:

    • 感谢您的精彩解释。我认为将开闭逻辑封装在一个单独的钩子中没有多大用处,因为它只是一个 useState。我想知道 useCallback 是否可以做一些事情......
    • 你可以用useCallback钩子包裹someDialog的函数并将open设置为它的依赖,但我不确定它是否是一个好的解决方案。
    【解决方案2】:

    自定义钩子不是为返回组件而设计的,而是用于创建一个由不同组件共享的通用逻辑。

    在您的情况下,我建议您为对话框创建一个通用组件。并在任何你想要的地方使用这个组件。像这样:

    <CustomDialog open={open}>
    // Your jsx here
    </CustomDialog>
    
    const CustomDialog = ({children}) => {
    return <Dialog open={open} onClose={handleClose}>
                <DialogTitle>{title}</DialogTitle>
                <DialogContent>{children}</DialogContent>
                <DialogActions>
                  <Button onClick={handleClose} color="primary">
                    Close
                  </Button>
                </DialogActions>
              </Dialog>
    }
    

    有关自定义挂钩的更多信息:

    https://reactjs.org/docs/hooks-custom.html

    【讨论】:

      猜你喜欢
      • 2020-03-06
      • 2021-02-06
      • 1970-01-01
      • 2020-07-23
      • 1970-01-01
      • 2021-12-16
      • 1970-01-01
      • 1970-01-01
      • 2019-11-29
      相关资源
      最近更新 更多