javascript - React 浅拷贝仍然触发重新渲染?
问题描述
根据我对 React 的了解,您不应该改变任何对象,否则 React 不知道重新渲染,例如,当单击按钮时,以下示例不应触发 UI 中的重新渲染:
import React, { useState } from "react";
import ReactDOM from "react-dom";
function App({ input }) {
const [items, setItems] = useState(input);
return (
<div>
{items.map((item) => (
<MyItem item={item}/>
))}
<button
onClick={() => {
setItems((prevItems) => {
return prevItems.map((item) => {
if (item.id === 2) {
item.name = Math.random();
}
return item;
});
});
}}
>
Update wouldn't work due to shallow copy
</button>
</div>
);
}
function MyItem ({item}) {
const name = item.name
return <p>{name}</p>
}
ReactDOM.render(
<App
input={[
{ name: "apple", id: 1 },
{ name: "banana", id: 2 }
]}
/>,
document.getElementById("container")
);
你可以在这里尝试上面的代码
并且更新对象数组的正确方法应该如下所示(其他深度复制方法也可以)
setItems((prevItems) => {
return prevItems.map((item) => {
if (item.id === 2) {
# This way we return a deepcopy of item
return {...item, name: Math.random()}
}
return item;
});
});
为什么即使我只是更新原始项目对象,第一个版本也可以正常工作并且 UI 会立即更新?
解决方案
渲染是.map
因为创建了新数组。如果您prev[1].name = "x"; return prev;
在钩子中执行类似操作,则不会执行更新。每个带有函数参数的reactjs doc :setState
如果您的更新函数返回与当前状态完全相同的值,则将完全跳过后续的重新渲染。
更新。
是的,说到亲子互动,item
将是相同的(通过引用),但孩子props
会有所不同。你有MyItem({ item })
,这item
正在被解构props
,比如MyItem(props)
,并且props
由于父源发生了更改,因此发生了更改。
因此,每次map
列出列表时,您都明确要求父级渲染其子级,而子级的部分(或全部)参数未更改这一事实并不重要。为了证明这一点,您可以从子组件中删除任何参数:
{items.map(() => ( <MyItem /> ))}
function MyItem () {
return <p>hello</p>
}
MyItem
items
每次通过状态挂钩执行更新时都会调用。而且它props
总是与以前的版本不同。
推荐阅读
- angular - 在 Angular 2+ 中继承组件
- postgresql - 在不执行查询的情况下获取 QUERY PLAN?
- r - 使用 gkmSVM 为小鼠基因组 mm10 创建空序列
- reactjs - 在 React Effect Hook 中使用箭头函数是否有任何性能问题?
- sql - 如何提取下表中都有日期差异的记录?
- javascript - 使用 twitch api 时,Google Chrome 会变黑 1 秒,并以绿色阴影显示我的所有剪辑(iframe)
- git - Git - 避免发生冲突?
- python - 在图像中查找 python
- electron - 如果非管理员用户以提升的权限 (uiAccess=true) 打开 Electron 将忽略 loadURL() 调用
- javascript - 如何从 SQL 查询中填充复选框组