React受控输入转非受控警告A component is changing排查
问题原因
这个警告是React受控组件的通用规则校验:只要表单元素被标记为受控组件(传入了value属性),其整个生命周期内value都不能是undefined,否则就会被判定为从受控模式意外切换到非受控模式,抛出你看到的提示。
你的代码里有两处直接触发警告的问题:
- 初始输入就触发警告:三元渲染的第三个分支(非激活、非resetBtn状态下的禁用输入框)完全没有传入
value属性,等价于value={undefined}。每次键入内容时父组件inputValue更新触发重渲染,只要当前输入框走到这个分支,就会出现「之前渲染时value是有定义的字符串,现在渲染时value是undefined」的情况,直接触发警告。 - 把第二个分支的
value=""换成defaultValue=""后警告延迟到回车时触发:defaultValue仅用于非受控组件的初始值赋值,传入它不会让组件变成受控模式。按下回车后组件状态更新重渲染,禁用分支的输入框没有合法的受控value传入,value变为undefined,警告就会在此时触发。
另外你代码里直接写e.target.disabled = true操作DOM的写法不符合React数据驱动的设计,很容易导致DOM实际状态和组件状态不一致,属于隐患写法。
修复方案
- 所有渲染分支下的
FormControl组件必须显式传入value属性,保证任何时候value都是字符串类型,不会出现undefined。你这里两个禁用分支的逻辑完全一致,不需要拆成两个三元分支,合并即可。 - 删除直接操作DOM的代码,完全通过组件状态控制输入框的禁用/启用,和React单向数据流逻辑对齐。
- 小优化:判断输入值前先把当前输入值存到变量里,避免
setInputValue异步执行导致取值异常。
修复后的核心代码如下:
const Wordleinput = (props) => { const targetWordString = "DOGS" const handleUserInput = (e) => { props.setInputValue(e.target.value.toUpperCase()) }; const handleKeyPress = (e) => { props.setReset(false) if (e.key === "Enter"){ const currentInput = e.target.value if(currentInput.length === 0){ alert("Put something in there first") return } props.setInputValue('') if(currentInput !== targetWordString){ props.setIteration(props.iteration + 1) } else { props.declareWin(true) } } } return ( <div> {props.winShown === false && props.id === props.iteration ? ( <FormControl placeholder="4 letter word" maxLength="4" className="w-25" value={props.inputValue} onChange={handleUserInput} onKeyPress={handleKeyPress} /> ) : ( <FormControl disabled value="" maxLength="4" className="w-25" /> )} </div> ) }
父组件的状态声明不需要改动,改完之后警告就会完全消失。
内容的提问来源于stack exchange,提问作者MasterlyVase6
相关产品推荐
相关产品推荐

