React报错Rendered more hooks than during the previous render问题求助
问题根本原因
你遇到的Rendered more hooks than during the previous render报错核心是违反了React Hook的调用规则:Hook只能在React函数组件的顶层、或者自定义Hook的顶层调用,不能在普通函数、条件判断、循环内调用。
具体错误点
- 你将包含
useState、间接调用useRef/useEffect的DefaultValue作为普通函数,直接传入<select>的value属性调用:渲染过程中动态调用带Hook的函数,会导致Hook调用顺序不稳定,触发报错。 - 普通函数
countryHasChanged内部调用了自定义HookUsePrevious,不符合Hook的调用规则要求。 useEffect的依赖数组包含了selectedPathway,同时effect内部又调用changeSelectedPathway修改selectedPathway,会触发无限重渲染。- 组件主体内直接编写
dispatch更新逻辑、直接修改levers数组元素的value属性,前者属于渲染阶段执行副作用会导致额外重渲染,后者属于直接突变状态违反React不可变数据原则。
修复方案
- 把
DefaultValue改成自定义Hook,不要当成普通值传入组件属性:
// 改成自定义Hook(首字母大写,内部调用Hook符合规则) const useDefaultValue = (options, countryLabel, value, levers, pathways, dispatch) => { let matchingOption = options.find((option) => option.value.includes(countryLabel)) let optionSelected = options.find((option) => option.value === value) // 把UsePrevious的逻辑移到顶层,不要在普通函数里调用Hook const prevCountryLabel = useRef() const hasCountryLabelChanged = prevCountryLabel.current !== countryLabel useEffect(() => { prevCountryLabel.current = countryLabel }, [countryLabel]) const [selectedPathway, changeSelectedPathway] = useState(matchingOption) // 依赖去掉selectedPathway,避免死循环 useEffect(() => { if (hasCountryLabelChanged) { changeSelectedPathway(matchingOption || options[0]) } else { changeSelectedPathway(optionSelected) } }, [matchingOption, optionSelected, hasCountryLabelChanged, options]) // 把更新逻辑移到useEffect里,不要在渲染阶段执行 useEffect(() => { if(selectedPathway === undefined) return // 不要突变原数组,返回新对象 const newLevers = levers.map((lever, index) => { return { ...lever, value: +pathways[selectedPathway.value][index].toFixed(1) * 10 } }) dispatch(Actions.updateAllLevers(newLevers)) }, [selectedPathway, levers, pathways, dispatch]) return selectedPathway }
- 在使用
<select>的父组件中调用这个自定义Hook获取值:
// 父组件内调用 const selectedPathway = useDefaultValue(options, countryLabel, value, levers, pathways, dispatch) // 渲染时直接传值 <select value={selectedPathway} />
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

