我有以下代码:
function MyComponent( props ) {
let arrSize = 5;
const [arr, setArr] = useState( () => {
let initial = new Array(arrSize);
for(let i=0; i<arrSize; i++) initial.push({ foo: 'foo', bar: 'bar'});
return initial;
});
mouseEventCallback = (e) => {
// ...
let tmp = arr;
// ...
setArr( tmp );
}
let cmp = [];
for(let i=0; i<arrSize; i++) {
cmp.push( <span key={i} className={arr[i].foo}></span> );
}
return (
<div>
{cmp}
</div>
)
}
当几次调用鼠标回调时,我遇到了一个问题:状态参数已更改为OK(检查带有响应组件的Chrome Web浏览器中的选项卡),但状态为DOM的元素并未全部重新呈现-其中一些具有旧状态。
当我添加虚拟状态时-一切正常:
function MyComponent( props ) {
let arrSize = 5;
const [arr, setArr] = useState( () => {
let initial = new Array(arrSize);
for(let i=0; i<arrSize; i++) initial.push({ foo: 'foo', bar: 'bar'});
return initial;
});
const [dummy, setDummy] = useState(0);
mouseEventCallback = (e) => {
// ...
let tmp = arr;
// ...
setArr( tmp );
setDummy( Math.rand() );
}
let cmp = [];
for(let i=0; i<arrSize; i++) {
cmp.push( <span key={i} className={arr[i].foo}></span> );
}
return (
<div dataTest={dummy}>
{cmp}
</div>
)
}
我如何改善代码并以正确的方式解决问题?
答案 0 :(得分:1)
您的组件不会在setArr(tmp)上重新呈现,因为“ tmp”变量引用的数组与“ arr”变量相同。相同的引用意味着它们指向内存中的同一事物,因此当react在旧状态和新状态之间进行比较时,它们将返回相同的事物,即tmp === arr返回true。如果旧状态=新状态组件将不重新呈现。所以为了重新渲染;使“ tmp”指向具有与“ arr”相同数据的新数组。您可以使用ES6传播算子。
更改:让tmp = arr; 若要:让tmp = [... arr];
let a = [1, 2, 3];
let b = a;
let c = [...a]; // ES6 Spread Operator
a === b; // returns true
a === c; // returns false
正确的代码:
function MyComponent( props ) {
let arrSize = 5;
const [arr, setArr] = useState( () => {
let initial = new Array(arrSize);
for(let i=0; i<arrSize; i++) initial.push({ foo: 'foo', bar: 'bar'});
return initial;
});
mouseEventCallback = (e) => {
// ...
let tmp = [...arr];
// ...
setArr( tmp );
}
let cmp = [];
for(let i=0; i<arrSize; i++) {
cmp.push( <span key={i} className={arr[i].foo}></span> );
}
return (
<div>
{cmp}
</div>
)
}