以下是概念证明笔。我试图显示很多输入字段,并尝试在一个大对象中更改它们时收集它们的输入。如您所见,输入将不会更改其值,这正是我所期望的,因为它们是使用useEffect()
创建一次并将其填充到该实例中的。
我认为解决此问题的唯一方法是在React.cloneElement
更改时使用 values
并将新值注入到克隆的元素中。这就是为什么我在这支笔中创建了2000个元素的原因,这将是主要的性能消耗,因为状态发生变化时,每个元素都会重新渲染。我试图使用React.memo
仅使更改后的值的输入重新呈现,但我认为cloneElement
只是反过来重新呈现它,听起来好像应该将其克隆。
如何在此设置中为单个字段实现性能更新?
https://codepen.io/10uur/pen/LYPrZdg
编辑:一支笔,它具有我之前提到的cloneElement
解决方案,明显的性能问题以及所有输入都被重新呈现。
答案 0 :(得分:1)
这是实现所需行为的一种方法: https://codesandbox.io/s/elastic-glade-73ivx
一些提示:
key
道具React.memo
可以避免在道具相同时重新渲染组件React.useCallback
来记住回调(在孩子上使用React.memo
时会有所帮助)React.useCallback
时有所帮助,并且避免在状态更改时重新创建回调)这是完整的代码:
import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const INPUTS_COUNT = 2000;
const getInitialState = () => {
const state = [];
for (var i = 0; i < INPUTS_COUNT; i++) {
// Only put plain data in the state
state.push({
value: Math.random(),
id: "valueContainer" + i
});
}
return state;
};
const Root = () => {
const [state, setState] = React.useState([]);
useEffect(() => {
setState(getInitialState());
}, []);
// Use React.useCallback to memoize the onChangeValue callback, notice the empty array as second parameter
const onChangeValue = React.useCallback((id, value) => {
// Use the functional form of the state setter, to update the old state
// if we don't use the functional form, we will be forced to put [state] in the second parameter of React.useCallback
// in that case React.useCallback will not be very useful, because it will recreate the callback whenever the state changes
setState(state => {
return state.map(item => {
if (item.id === id) {
return { ...item, value };
}
return item;
});
});
}, []);
return (
<>
{state.map(({ id, value }) => {
// Use a key for performance boost
return (
<ValueContainer
id={id}
key={id}
onChangeValue={onChangeValue}
value={value}
/>
);
})}
</>
);
};
// Use React.memo to avoid re-rendering the component when the props are the same
const ValueContainer = React.memo(({ id, onChangeValue, value }) => {
const onChange = e => {
onChangeValue(id, e.target.value);
};
return (
<>
<br />
Rerendered: {Math.random()}
<br />
<input type="text" value={value} onChange={onChange} />
<br />
</>
);
});
ReactDOM.render(<Root />, document.getElementById("root"));