React出现uncontrolled input转controlled警告,通用方案无效如何解决?
问题根源
- 最核心的错误是违反了React Hook的调用规则:你将
useState、useEffect写在了else条件分支中。Hook必须在组件的最顶层调用,不能包裹在条件、循环、嵌套函数内。当组件首次渲染传入的user为假值时,不会执行这两个Hook;后续user变为真值时才触发Hook调用,两次渲染的Hook执行顺序不一致,导致状态管理混乱,最终触发input的受控/非受控切换警告。 - 次要问题:
useEffect中更新name状态时没有对user.name做兜底处理,如果user.name为undefined/null,会直接将name设置为空值,进一步提升状态异常的概率。
修复方案
你需要调整代码结构,把所有Hook移到组件最顶层,再补充状态更新时的兜底逻辑即可,修改后的代码如下:
import { useState, useEffect } from 'react' export default({user}) => { // 所有Hook移到组件最顶层 const [name,setName] = useState(user?.name || "") useEffect(() => { // 状态更新时补充兜底 setName(user?.name || ""); }, [user]) // 空值判断放在Hook之后 if(!user) { return <div></div> } return <form> <fieldset> <legend> Edit {user.name }</legend> <p> <label htmlFor="name"> Name </label> <input id="name" value={name} onChange={e => setName(e.target.value)} /> </p> </fieldset> </form> }
额外说明
你之前在input的value属性上加的|| ""兜底可以去掉,因为现在初始化和状态更新时都做了兜底,name状态永远不会是空值,input会始终保持受控状态。
内容的提问来源于stack exchange,提问作者Osman Corluk
相关产品推荐
相关产品推荐

