reactjs - 这是更新状态的正确方法吗?
问题描述
我的组件如下所示:
import cloneDeep from "clone-deep";
import { Context } from "../../context";
const Component = () => {
const context = useContext(Context);
const [state, setState] = useState(
{
_id: "123",
users: [
{
_id: "1",
points: 5
},
{
_id: "2",
points: 8
}
]
}
);
useEffect(() => {
context.socket.emit("points");
context.socket.on("points", (socketData) => {
setState(prevState => {
const newState = {...prevState};
const index = newState.users
.findIndex(user => user._id == socketData.content._id);
newState.users[index].points = socketData.content.points;
return newState;
})
});
return () => context.socket.off("points");
}, []);
return <div>(There is table with identificators and points)</div>
};
我想知道这是否是正确的方法。我只想以正确的方式编写代码。或者使用深度克隆可能会更好?有关系吗?
setState(prevState => {
const newState = cloneDeep(prevState);
const index = newState.users
.findIndex(user => user._id == "2");
newState.users[index].points++;
return newState;
})
编辑:我添加了其余代码以使其更易于理解。
解决方案
在您当前的代码中:
useEffect(() => {
setState((prevState) => {
const newState = { ...prevState };
const index = newState.users.findIndex((user) => user._id == "2");
newState.users[index].points++;
console.log({ prevState, newState });
return newState;
});
}, []);
您可以看到它prevState
正在发生变异(点数为 9):
{
_id: "123",
users: [
{
_id: "1",
points: 5
},
{
_id: "2",
points: 9 // Mutated!
}
]
}
为了避免改变状态,你必须使用不改变的方法,例如扩展运算符或映射函数:
useEffect(() => {
setState((prevState) => {
const newState = ({
...prevState,
users: prevState.users.map((user) =>
user._id === "2"
? {
...user,
points: user.points + 1
}
: user
)
})
console.log({ prevState, newState });
return newState
}
);
}, []);
现在您可以看到 prevState 没有发生突变:
{
_id: "123",
users: [
{
_id: "1",
points: 5
},
{
_id: "2",
points: 8 // Not mutated :)
}
]
}
推荐阅读
- xcode - Xcode 11:clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- php - 如何获取 G Suite 用户的电子邮件使用量和容量?
- android - Android Room InvalidationTracker 和 Flow 流未在 @Update 上通知
- arrays - 有没有更好的方法来可视化数组?
- python - 通过 websocket 抓取数据
- python-3.x - 在python中对DataFrame进行切片是返回副本还是对原始DataFrame的引用
- python - 如何在多索引数据帧的最外层使用 iloc 切片?
- java - 使用 ClientCredentialProvider 发送电子邮件无法找到租户 guid
- python - 转换为字典python中的可执行值
- kubernetes - 使用 OPA 进行 Envoy 外部授权 - 使用大型 JSON 主体评估失败