我有一个简单的问题与React渲染有关。在我解释之前,这是代码沙箱的链接:https://codesandbox.io/s/list-rerendering-y3iust?file = / src / App.js
事实是,我有一个存储在父组件App中的对象数组。每个对象都有一个“checked”字段,我希望在单击该对象的相应复选框时切换它。我循环遍历对象数组并在Child组件中显示它们。当我单击复选框时,handleChange函数执行,并且列表在父组件中更新,导致App重新呈现以及所有 Child组件。 我想要解决的问题是,如何使其仅重新呈现被单击的Child组件而不是所有Child组件?
我尝试使用useCallback和列表状态的功能性更新,但这没有做任何事情,它仍然重新呈现所有子组件而不是正在切换的子组件。我有一种感觉,我使用useCallback不正确,并且正在创建全新的函数。我想了解React在处理数组时如何重新呈现,将先前的数组与新数组进行比较的解释。我理解,在我的代码中,我通过解构将其提供给原始列表的副本,然后将其放入新数组中,这显然不是对原始列表的引用,因此React将副本设置为新状态:
import { useCallback, useState } from "react";
import Child from "./Child";
import "./styles.css";
const mockList = [
{ text: "1", id: 1, checked: false },
{ text: "2", id: 2, checked: false },
{ text: "3", id: 3, checked: false },
{ text: "4", id: 4, checked: false },
{ text: "5", id: 5, checked: false }
];
export default function App() {
const [list, setList] = useState(mockList);
const handleChange = useCallback((checked, id) => {
setList((oldList) => {
for (let i = 0; i < oldList.length; i++) {
if (oldList[i].id === id) {
oldList[i].checked = checked;
break;
}
}
return [...oldList];
});
}, []);
return (
<div className="App">
{list.map((item) => (
<Child
key={item.id}
text={item.text}
checked={item.checked}
handleChange={(checked) => handleChange(checked, item.id)}
/>
))}
</div>
);
}
Child.js
const Child = ({ text, checked, handleChange }) => {
console.log("Child rerender");
return (
<div
style={{
display: "flex",
border: "1px solid green",
justifyContent: "space-around"
}}
>
<p>{text}</p>
<input
style={{ width: "20rem" }}
type="checkbox"
checked={checked}
onChange={(e) => handleChange(e.checked)}
/>
</div>
);
};
export default Child;
React.memo()
将Child
组件包装起来,使其成为一个纯组件,并在导出时进行包装。 - Irfanullah Jan