繁体   English   中英

如何在 React 组件的第一次渲染时不改变状态?

[英]How to not change the state at the first render of React component?

我正在尝试使用 React 创建一个 MUI 对话框组件并从包装组件管理它。 这是我的例子:

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

export default function MultiNote(props) {
    
    const [useDialogOpen, setDialogOpen] = useState(false);

    useEffect(() => {
        setDialogOpen(!useDialogOpen);
    }, [props.open]);

    const handleDialogToggle = () => {
        setDialogOpen(!useDialogOpen);
    }

    return (
        <Dialog
            open={useDialogOpen}
            onClose={handleDialogToggle}
            aria-labelledby="form-multinote-dialog"
        >
            <DialogTitle id="form-multinote-dialog">{props.title}</DialogTitle>
            <DialogContent>Test</DialogContent>
            <DialogActions>
                <Button onClick={handleDialogToggle} color="primary">
                    Close
                </Button>
            </DialogActions>
        </Dialog>
    );
}

在这里,我正在尝试根据组件的 prop 的打开状态更改 useDialogOpen 状态。 除了第一次渲染外,它工作得很好。 在第一次渲染时,它会打开对话框。 但我希望它被关闭。

我不明白为什么它会改变。

我使用沙箱来测试您的代码。 您的 useEffect 正在将 useDialogOpen 切换为 true。

我在你的 useEffect 中使用了一个 if 语句来让它不显示对话框:

useEffect(() => {
    if (Object.keys(props).length !== 0) {
      setDialogOpen(!useDialogOpen);
    }
  }, [props.open]);

这是有效的,因为它确认了一个 prop 实际上正在被传递到组件中,而不仅仅是一个空对象。

这是一个包含所有代码的沙箱供您使用:

https://codesandbox.io/s/stoic-shaw-3dszx?file=/src/App.js:259-279

发生这种情况的原因是因为您正在观察 props.open 的更改,因为它总是在渲染阶段传入。 然后将您的 useDialog 切换为 true 并显示对话框。

回答你的第一个问题 - 为什么对话框在第一次渲染时打开? 发生的事情是这样的:

  1. 组件第一次渲染,并且useDialogOpen为 false(因为它是用useState(false)创建的),并且对话框已关闭)。
  2. 紧接着(可能如此之快以至于用户无法感知),您的useEffect运行,并调用setDialogOpen(!useDialogOpen) 由于useDialogOpen当前为 false,这与setDialogOpen(true)相同
  3. 组件使用useDialogOpen为 true 重新呈现。

如果您希望对话框打开状态由open属性控制,您可能需要考虑提升 state 例如,摆脱这个组件内的所有状态,并向道具添加一个 onClose 事件。 所以它看起来像这样:

function MultiNote(props) {
  return (
    <Dialog
      open={props.open}
      onClose={props.onClose}
      aria-labelledby="form-multinote-dialog"
    >
      <DialogTitle id="form-multinote-dialog">{props.title}</DialogTitle>
      <DialogContent>Test</DialogContent>
      <DialogActions>
        <Button onClick={props.onClose} color="primary">
          Close
        </Button>
      </DialogActions>
    </Dialog>
  );
}

它可以像这样使用:

function App() {
  const [isOpen, setIsOpen] = useState(false);
  return <MultiNote open={isOpen} onClose={() => setIsOpen(false)} />;
}

看到这个代码和框

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM