React State Hooks数组元素不更新问题及多输入框优化方案咨询
问题根因
核心问题是违反了React状态的不可变更新原则:
- 数组属于引用类型,你写的
let temp = inputs只是把temp指向了和state中inputs完全相同的数组对象,没有生成新的数组 - 直接修改原数组后把同一个引用传给状态更新方法,React会判定状态没有变化,不会触发组件重渲染,因此视图不会同步更新
- 你在set_error中能打印出修改后的数组,是因为修改操作是同步执行的,你打印的是已经被原地修改的原数组,和React是否触发重渲染无关
基础修复方案
只需要修改两个状态更新函数的逻辑,拷贝原数组生成新数组后再更新,即可正常运行:
// 修正输入值更新逻辑 const set_input = (index, text) => { // 展开原数组生成全新数组,不修改原state let temp = [...inputs]; temp[index] = text; set_input_arr(temp); }; // 修正错误信息更新逻辑 const set_error = (index, err) => { let temp = [...error]; temp[index] = err; set_error_arr(temp); };
进一步精简优化方案
你还可以把输入框的配置抽成数组,通过循环渲染输入框,不用逐个手写,后续新增字段只要修改配置数组即可,代码量会大幅减少:
import { OutlinedTextField } from 'rn-material-ui-textfield' // ...其余所有导入 const example = () => { // 抽离所有输入框配置,后续加字段直接往这个数组新增即可 const fieldConfigs = [ { label: '姓名', errorTip: 'your name' }, { label: '邮箱', errorTip: 'an email ID' }, { label: '密码', errorTip: 'a password' }, { label: '手机号', errorTip: 'your phone number' }, { label: '最喜欢的颜色', errorTip: "your favourite color" }, { label: '昵称', errorTip: 'your nickname' }, ] // 基于配置长度自动初始化state,不用手动写多个空字符串 let [inputs, set_input_arr] = React.useState(Array(fieldConfigs.length).fill('')); let [errors, set_error_arr] = React.useState(Array(fieldConfigs.length).fill('')); const set_input = (index, text) => { const newInputs = [...inputs]; newInputs[index] = text; set_input_arr(newInputs); }; const verify = () => { let isValid = true; // 一次性生成所有错误信息再更新state,减少重渲染次数 const newErrors = inputs.map((val, index) => { if (!val.trim()) { isValid = false; return `请输入${fieldConfigs[index].errorTip}`; } return ''; }) set_error_arr(newErrors); if (isValid) { console.log('校验通过', inputs); // 后续提交逻辑写在这里 } }; return( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> {/* 循环渲染所有输入框,不用逐个手写 */} {fieldConfigs.map((config, index) => ( <OutlinedTextField key={index} label={config.label} onChangeText={text => set_input(index, text)} value={inputs[index]} error={errors[index]} // 最后一个输入框绑定提交校验 onSubmitEditing={index === fieldConfigs.length - 1 ? verify : undefined} /> ))} <Button onPress={verify} title='校验' /> </View> ); }
内容的提问来源于stack exchange,提问作者Vishal DS
相关产品推荐
相关产品推荐

