React中如何使用useRef在初始渲染后更新input defaultValue
问题原因
React中非受控组件的defaultValue属性仅在组件首次挂载时生效,作用是初始化输入框的值,后续组件重渲染时如果defaultValue发生变化,React不会主动同步更新已经挂载的输入框的实际值。你的代码中输入框始终没有被卸载重挂,所以只有第一次点击编辑时的初始化值能生效,后续切换编辑条目时值不会更新。
这个需求完全可以仅通过useRef实现,不需要改成受控组件,也不需要用placeholder降级交互效果。
可行实现方案
方案1:通过ref直接操作输入框赋值(推荐,完全符合非受控+useRef要求)
非受控组件的核心逻辑就是直接操作DOM,你可以在触发编辑动作时,拿到待编辑的条目内容后,直接通过ref给输入框的value属性赋值,不需要依赖defaultValue的响应式更新。
核心修改点:
- 调整
editItem方法,在设置编辑状态后直接通过ref给输入框赋值、聚焦 - 提交表单后,通过ref手动清空输入框内容——原代码中修改局部变量
nameValue的写法是无效的,不会改动输入框的实际显示值
修改后的核心代码如下:
const editItem = (id) => { const targetItem = list.find((item) => item.id === id); setItemToEdit(targetItem); setIsEditing(true); // 直接操作DOM给输入框填充待编辑内容 refContainer.current.value = targetItem.name; refContainer.current.focus(); }; const handleSubmit = (e)=>{ e.preventDefault(); const nameValue = refContainer.current.value.trim(); if (!nameValue) return; // 增加空值校验,避免提交空内容 if (isEditing){ setList(list.map((item)=>{ if (item.id === itemToEdit.id){ return {...item, name: nameValue}; } return item; })); } else { const newItem = { // 修复原代码bug:Date对象没有getItem方法,用getTime生成时间戳id id: new Date().getTime().toString(), name: nameValue, } setList([...list, newItem]) } // 提交后清空输入框,重置编辑状态 refContainer.current.value = ""; setIsEditing(false); }
输入框部分保留简单的默认值设置即可,不影响功能:
<input type="text" ref={refContainer} defaultValue="" />
方案2:给输入框加key触发重挂载(备选)
如果你不想手动操作输入框的value,可以给输入框绑定一个随编辑目标变化的key属性,React会在key变化时自动卸载旧输入框、挂载新输入框,这时候defaultValue就会重新初始化生效:
<input type="text" ref={refContainer} // 编辑时绑定当前条目id,新建状态用固定key key={isEditing ? `edit-${itemToEdit.id}` : 'create'} defaultValue={isEditing ? itemToEdit.name : ""} />
注意:这个方案每次切换编辑目标都会销毁重建输入框,性能略差,属于取巧实现,更推荐第一种直接操作ref的方案。
关于placeholder的说明
完全不需要用placeholder替代。placeholder是浅灰色的提示文本,用户很容易混淆提示内容和实际输入内容,交互体验很差,用上面两种方案都可以实现正常的待编辑内容填充效果。
原代码其他注意点
- 你当前代码中调用了
deleteItem方法但没有实现,需要补充对应的删除逻辑,删除时通过setList过滤掉对应id的条目即可 - 本地存储读取的
getLocalStorage方法需要加异常捕获,避免JSON.parse解析损坏的本地数据导致页面报错
内容的提问来源于stack exchange,提问作者jaehyuk kim
相关产品推荐
相关产品推荐

