如何避免React组件首次渲染时修改state?MUI Dialog受控场景问题
问题根因
- 你的useEffect逻辑完全错误:你期望将内部状态和props.open同步,但现有代码并没有将内部状态设置为props.open的值,而是在每次props.open变化时直接取反当前内部状态。
- React的useEffect会在组件首次挂载完成后默认执行一次,不受依赖项是否变化影响。你初始化内部状态为false,首次执行useEffect时直接取反为true,自然会导致首次渲染后弹窗自动打开。
修复方案
方案1:保持内部状态同步props(适合需要组件内部管控部分关闭逻辑的场景)
直接在useEffect中将内部状态赋值为props.open的值即可,同时建议修改状态命名避免和自定义Hook规范冲突:
import { Dialog, DialogActions, DialogTitle, DialogContent, Button } from "@material-ui/core"; import React, {useState, useEffect} from "react"; export default function MultiNote(props) { // 状态名去掉use前缀,避免和自定义Hook命名规范混淆 const [dialogOpen, setDialogOpen] = useState(false); useEffect(() => { // 直接同步props.open的值,不要取反 setDialogOpen(props.open); }, [props.open]); const handleDialogToggle = () => { setDialogOpen(!dialogOpen); } return ( <Dialog open={dialogOpen} 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> ); }
方案2:完全受控组件(更推荐,避免内外状态不同步问题)
如果弹窗的开启关闭逻辑完全由父组件管控,你完全不需要在内部维护状态,直接绑定props属性即可,代码更简洁:
import { Dialog, DialogActions, DialogTitle, DialogContent, Button } from "@material-ui/core"; import React from "react"; export default function MultiNote(props) { return ( <Dialog open={props.open} // 关闭时调用父组件传入的关闭回调,由父组件修改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> ); }
父组件使用时传入open和onClose属性即可。
内容的提问来源于stack exchange,提问作者sundowatch
相关产品推荐
相关产品推荐

