Проблема связана с:
function handleChange(obj) {
return (event) => setObjects(objs.map((o) => {
if (o === obj) return {...obj, value: event.target.value}
return o;
}));
}
В этом примере вы обновите массив objs
.Это, конечно, хорошо, но React не знает, что изменилось, поэтому сработал Render на всех дочерних элементах.
Если ваш функциональный компонент отображает один и тот же результат с теми же параметрами, вы можете заключить его в вызовReact.memo для повышения производительности.
https://reactjs.org/docs/react-api.html#reactmemo
const MyInput = React.memo(({obj, onChange}) => {
console.log(`Rerendered: ${obj.label}`);
return <div style={{display: 'flex'}}>
<label>{obj.label}</label>
<input type="text" value={obj.value} onChange={onChange} />
</div>;
}, (prevProps, nextProps) => prevProps.obj.label === nextProps.obj.label && prevProps.obj.value === nextProps.obj.value);
Однако React.Memo делает поверхностное сравнение только при попытке выяснить, должен ли он отображаться, поэтому мы можем передатьпользовательская функция сравнения в качестве второго аргумента.
(prevProps, nextProps) => prevProps.obj.label === nextProps.obj.label && prevProps.obj.value === nextProps.obj.value);
Говоря в основном, если метка и значение в obj
prop такие же, как и предыдущие атрибуты предыдущего obj
prop,не перерисовывать.
Наконец, setObjects
так же, как setState, также является асинхронным и не будет немедленно отражать и обновлять.Таким образом, чтобы избежать риска некорректности objs
и использования более старых значений, вы можете изменить это на обратный вызов, например:
function handleChange(obj) {
return (event) => {
const value = event.target.value;
setObjects(prevObjs => (prevObjs.map((o) => {
if (o === obj) return {...obj, value }
return o;
})))
};
}
https://codepen.io/anon/pen/QPBLwy?editors=0011 имеет все это, а такжеconsole.logs, показывающий, если что-то перерисовано.
Есть ли более эффективный способ приблизиться к этому?
Вы храните все свои значения в массиве,это означает, что вы не знаете, какой элемент нужно обновить, не просматривая весь массив, сравнивая, соответствует ли объект.
Если вы начали с Объекта:
const startingObjects =
new Array(100).fill(null).reduce((objects, _, index) => ({...objects, [index]: {value: 'value', label: index}}), {})
Через некоторое времяВ модификациях ваша функция дескриптора изменится на
function handleChange(obj, index) {
return (event) => {
const value = event.target.value;
setObjects(prevObjs => ({...prevObjs, [index]: {...obj, value}}));
}
}
https://codepen.io/anon/pen/LvBPEB?editors=0011 в качестве примера.