React useState声明的状态变量value渲染时变为undefined报错排查
问题原因
- 本地state
value初始值设为空字符串,但同步props.value的useEffect没有做值校验:当父组件首次渲染未传入props.value、或重渲染时传入的props.value为undefined,effect会直接执行setValue(undefined),把初始的空字符串state覆盖为undefined,此时渲染阶段访问value.length就会触发"Cannot read properties of undefined"报错。 - 你之前判断首次渲染
value.length应该返回0的逻辑只适用于组件第一次渲染的阶段:useEffect在首次渲染提交到DOM后才会执行,第一次渲染时确实用的是空字符串不会报错,但effect执行完把state改成undefined后会触发第二次渲染,这时候访问undefined的length属性就会直接抛错。 - 移除
value.length相关代码后不再报错,是因为React接收到textarea的value属性为undefined时,会自动把输入框切换为非受控模式,直接使用DOM本身的value渲染,刚好能展示传入的props内容,但这种写法本身不符合React受控组件规范,会埋下状态不一致的隐患。 - 存储sessionStorage的useEffect依赖数组直接传入了整个
props对象,React每次渲染都会生成新的props引用,会导致这个effect在每次渲染时都无意义触发,额外提升问题出现的概率。
修复步骤
- 给props同步逻辑加类型校验,避免非法值写入state
将同步props的useEffect修改为如下逻辑,只有当传入的props.value是合法字符串时才更新本地state:useEffect(() => { if (typeof props.value === 'string') { setValue(props.value); } }, [props.value]); - 所有访问
value.length的位置加安全兜底,做双重容错
用可选链+空值合并的写法,就算state意外被设为非字符串值,也不会因为访问length属性报错:
textarea标签上的className判断逻辑也用同样的写法替换即可。// 示例:span标签的className判断 className={ (value?.length ?? 0) === 0 ? "input-box--placeholder" : "input-box--placeholder input-box--placeholder--not-empty" } - 修正sessionStorage存储逻辑的依赖项,移除整个props对象的依赖,只保留实际用到的字段,避免无效的effect执行:
useEffect(() => { window.sessionStorage.setItem(props.name, value); }, [value, props.name]); - 可选优化:如果这个文本域组件是完全受控组件(父组件会传入value和对应的onChange回调),可以直接移除本地的
valuestate,所有逻辑直接基于props.value实现,从根源上消除本地state和props同步带来的不一致问题。
内容的提问来源于stack exchange,提问作者Jonan Mathew George
相关产品推荐
相关产品推荐

