Re-rendering 仅更新 React 表单上的元素
Re-rendering only updated elements on react form
我想实现一个动态构建的表单,其中包含可扩展的受控组件。我遇到的问题是更新状态导致整个表单 re-render(或昂贵的东西?)导致史诗类型滞后。
// Generate some example fields
let defaultFields = {};
for(let n=0; n<1000; n++){
defaultFields[n.toString()] = {'id':n.toString(), 'value':'','label':'Field '+n}
}
const [valuesById, setValuesById] = useState(defaultFields);
const updateValueCallback = React.useCallback((e)=>{
e.preventDefault();
e.persist();
setValuesById(prevValuesById => {
let fieldId = e.target.id;
return {...prevValuesById,
[fieldId]:{
'id':fieldId,
'value':e.target.value,
'label':'Field '+fieldId
}};
});
});
return <div>
{ Object.entries(valuesById).map(([id,formField]) => {
return <p key={formField.id}>
<label>{formField.label}
<SingleLineStringInput isRequired={false} value={formField.value} onChangeCallback={updateValueCallback} id={formField.id} name={'name_'+formField.id} />
</label>
</p>
})
}
</div>;
如果 999 个字段的道具都没有改变,那为什么 re-render?或者这里实际发生了什么(这些字段实际上并没有在调试工具中闪烁,但 parent 会)?我真的需要帮助来更好地理解这一点,并且需要一个与我所做的没有太大不同的修复,因为我们已经在这个基本结构之上构建了大量逻辑,并且现在才意识到它没有扩展。
单线输入:
const SingleLineStringInput = React.memo(({name, id, value, onChangeCallback}) => {
console.log("UPDATING "+id);
return <input className={'input ' + inputClasses.join(' ')} name={name} id={id} type="text"
value={(value === null) ? '' : value}
onChange={onChangeCallback} />
});
好的,我会尽力提供帮助,你使用 memo 和 useCallback 做得很好,但你没有将 依赖数组传递给 useCallback,因为你的回调对于每个渲染,你可以传递一个空数组给它,所以它在每个渲染上都是相同的函数,
你可以这样做
const updateValueCallback = React.useCallback((e)=>{
e.preventDefault();
e.persist();
setValuesById(prevValuesById => {
let fieldId = e.target.id;
return {...prevValuesById,
[fieldId]:{
'id':fieldId,
'value':e.target.value,
'label':'Field '+fieldId
}};
});
}, []); // dependencies array
现在,如果您更改字段值,将重新呈现该字段值
Sandbox 向您展示它是如何完成的
希望对您有所帮助
我想实现一个动态构建的表单,其中包含可扩展的受控组件。我遇到的问题是更新状态导致整个表单 re-render(或昂贵的东西?)导致史诗类型滞后。
// Generate some example fields
let defaultFields = {};
for(let n=0; n<1000; n++){
defaultFields[n.toString()] = {'id':n.toString(), 'value':'','label':'Field '+n}
}
const [valuesById, setValuesById] = useState(defaultFields);
const updateValueCallback = React.useCallback((e)=>{
e.preventDefault();
e.persist();
setValuesById(prevValuesById => {
let fieldId = e.target.id;
return {...prevValuesById,
[fieldId]:{
'id':fieldId,
'value':e.target.value,
'label':'Field '+fieldId
}};
});
});
return <div>
{ Object.entries(valuesById).map(([id,formField]) => {
return <p key={formField.id}>
<label>{formField.label}
<SingleLineStringInput isRequired={false} value={formField.value} onChangeCallback={updateValueCallback} id={formField.id} name={'name_'+formField.id} />
</label>
</p>
})
}
</div>;
如果 999 个字段的道具都没有改变,那为什么 re-render?或者这里实际发生了什么(这些字段实际上并没有在调试工具中闪烁,但 parent 会)?我真的需要帮助来更好地理解这一点,并且需要一个与我所做的没有太大不同的修复,因为我们已经在这个基本结构之上构建了大量逻辑,并且现在才意识到它没有扩展。
单线输入:
const SingleLineStringInput = React.memo(({name, id, value, onChangeCallback}) => {
console.log("UPDATING "+id);
return <input className={'input ' + inputClasses.join(' ')} name={name} id={id} type="text"
value={(value === null) ? '' : value}
onChange={onChangeCallback} />
});
好的,我会尽力提供帮助,你使用 memo 和 useCallback 做得很好,但你没有将 依赖数组传递给 useCallback,因为你的回调对于每个渲染,你可以传递一个空数组给它,所以它在每个渲染上都是相同的函数, 你可以这样做
const updateValueCallback = React.useCallback((e)=>{
e.preventDefault();
e.persist();
setValuesById(prevValuesById => {
let fieldId = e.target.id;
return {...prevValuesById,
[fieldId]:{
'id':fieldId,
'value':e.target.value,
'label':'Field '+fieldId
}};
});
}, []); // dependencies array
现在,如果您更改字段值,将重新呈现该字段值
Sandbox 向您展示它是如何完成的
希望对您有所帮助