React编辑表单触发Maximum Update Depth Exceeded警告问题
报错根因
- 组件顶层的sessionStorage清理逻辑、表单初始数据读取逻辑没有包裹在只执行一次的useEffect里,每次组件重渲染都会重复执行这部分逻辑,触发子组件JobForm重渲染
- 子组件JobForm每次数据变更都会调用父组件传入的
getNewData方法修改newData状态,状态更新又会触发父组件重渲染,直接形成「状态更新→父组件重渲染→子组件重渲染→状态更新」的无限循环,触发最大更新深度超限报错 - 现有useEffect依赖为空,但内部用到了
newData变量,属于遗漏依赖的写法,也会导致逻辑不符合预期
修复方案
- 把顶层的sessionStorage清理、初始数据getData的逻辑全部包裹在空依赖的useEffect里,保证只在组件首次挂载时执行一次
- 调整useEffect的依赖,把
newData加入依赖数组,保证newData变更时才更新storeData的值 - 初始的
newData状态类型改为对象,和表单返回的键值对结构匹配,避免逻辑异常
修复后完整代码
import { React, useEffect, useRef, useState } from "react"; import { globalFormStyling } from "../../../GlobalCommonStyling"; import { useHistory } from "react-router"; import { Navbar, SideBar } from "../../../../componenets/CommonComponents"; import JobForm from "../JobForm"; import { Grid } from "@material-ui/core"; import { FormInputButton, HollowButton, } from "../../../../componenets/Theme/WebButtons"; import { jobEditedColumn } from "../JobValidation"; export default function EditJob(props) { let history = useHistory(); const classes = globalFormStyling(); const [newData, getNewData] = useState({}); // 初始值改为对象匹配表单结构 const [getData, setGetData] = useState(null); const storeData = useRef(null); // 首次挂载执行的初始化逻辑,不会重复执行 useEffect(() => { // 清理sessionStorage逻辑移到这里 for (var i=0; i< sessionStorage.length; i++) { if(["JobInfo","EditJobFormVal","stateVars"].indexOf(sessionStorage.key(i))<0) { sessionStorage.removeItem(sessionStorage.key(i)) } } // 读取初始表单数据逻辑移到这里 let initialData; if(sessionStorage.getItem("JobInfo")) { initialData = JSON.parse(sessionStorage.getItem("JobInfo")) }else { initialData = props.location.state.inputData; sessionStorage.setItem("JobInfo", JSON.stringify(initialData)); } setGetData(initialData); storeData.current = initialData; }, [props.location.state?.inputData]); // 新增依赖newData,只有newData变更才会更新ref的值 useEffect(() => { if (!newData || !storeData.current) return; for (const [key] of Object.entries(newData)) { storeData.current[0][jobEditedColumn[key]] = newData[key]; } }, [newData]); function onSuccess(isWarning) { sessionStorage.setItem("JobInfo", JSON.stringify(storeData.current)); history.push("/SelfService/Jobs/JobInfo") } // 初始数据没加载完返回空,避免子组件接收到undefined报错 if (!getData) return null; return ( <div> <Navbar head={"Edit Job"} /> <SideBar selected={7} /> <div className={classes.gridLevelScreenDividing}> <div></div> <div> <JobForm marginTop="5.5%" minHeight="75%" existingDat={getData} getNewData={getNewData} onSuccess={onSuccess}/> </div> <div></div> </div> <div className={classes.bottomButtonStyling}> <Grid container> <Grid item sm={3} xs={1}> <div></div> </Grid> <Grid item container justify="center" spacing={3}> <Grid item> <HollowButton borderColor="black" inputWidth="136px" onClick={() => { history.push("/SelfService/Jobs/JobInfo"); }} style={{ marginTop: "13%" }} > Cancel </HollowButton> </Grid> <Grid item> <FormInputButton borderColor="black" inputWidth="136px" style={{ marginTop: "13%" }} type="submit" form={"jobDetailsForm"} /> </Grid> </Grid> <Grid item sm={3} xs={1}> <div></div> </Grid> </Grid> </div> </div> ); }
内容的提问来源于stack exchange,提问作者ShalikhShab
相关产品推荐
相关产品推荐

