javascript - React js hooks lodash 设置奇怪的行为
问题描述
我使用 lodash 能够将属性(对象、数组)的值更改为一定的深度,但我的行为很奇怪。
情况是这样的,我使用带有钩子的 react js,在状态下我有一个保存用户信息的对象,所以我做了一个 fetch 以将用户信息加载到状态为user
.
但是,此信息不仅保存在user
对象中,而且还保存在另一个名为 的对象中userInfo
,因此我有此信息处于两次状态但具有不同的主格属性。
什么我需要两次这个信息,只是为了确保当用户想要更改他们的数据(个人资料页面)时,我检查他修改的数据是否真的被修改了,即至少有一个元素不同从原来的。
问题出在哪里,当我编辑一个user
打开的数据时,它会更改相同的数据userInfo
,但我不明白原因。
最奇怪的是,这个问题只发生在我正在工作的本地项目上,在代码沙盒上做了一个简单的例子,这个问题没有发生。
问题似乎是由于handleChangeField
功能,但我不明白为什么只有本地发生。
你能帮我吗?
链接:codesandbox
代码:
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
import ReactJson from "react-json-view";
import lodash from "lodash";
const useStyles = makeStyles(theme => ({
root: {
"& > *": {
margin: theme.spacing(1),
width: 200
}
}
}));
export default function BasicTextFields() {
const classes = useStyles();
const [state, setState] = React.useState({
user: {
name: "James",
surname: "bond",
card: {
id: 7,
group: "J"
},
scope: [{ scope: "user", actions: ["create", "delete"] }]
},
userInfo: {
name: "James",
surname: "bond",
card: {
id: 7,
group: "J"
},
scope: [{ scope: "user", actions: ["create", "delete"] }]
}
});
const handleChangeField = field => ({ target: { value } }) => {
let newState = lodash.cloneDeep(state);
lodash.set(newState, field, value);
console.log(newState, state);
setState(newState);
};
console.log("Change", state);
return (
<form className={classes.root} noValidate autoComplete="off">
<ReactJson
src={state}
theme={"solarized"}
enableClipboard={false}
displayObjectSize={false}
/>
<TextField
id="standard-basic"
label="Name"
onChange={handleChangeField("user.name")}
/>
<TextField
id="standard-basic"
label="Group"
onChange={handleChangeField("user.card.group")}
/>
<TextField
id="standard-basic"
label="Action[0]"
onChange={handleChangeField("user.scope[0].actions[0]")}
/>
</form>
);
}
解决方案
问题出在哪里,当我编辑一个
user
打开的数据时,它会更改相同的数据userInfo
,但我不明白原因。
这告诉你user
and userInfo
(或user.card
and )在它发生的情况下userInfo.card
指的是同一个对象:
const userDataFromAjaxOrWhatever = {
name: "James",
surname: "bond",
card: {
id: 7,
group: "J"
},
scope: [{ scope: "user", actions: ["create", "delete"] }]
};
const state = {
user: userDataFromAjaxOrWhatever,
userInfo: userDataFromAjaxOrWhatever
};
console.log(`state.user.name = ${state.user.name}`);
console.log(`state.userInfo.name = ${state.userInfo.name}`);
console.log("Setting state.user.name = Joe");
state.user.name = "Joe";
console.log(`state.user.name = ${state.user.name}`); // Joe
console.log(`state.userInfo.name = ${state.userInfo.name}`); // Joe
您引用的代码不会发生这种情况,因为user
anduserInfo
指向不同的对象。我假设在您的真实代码中,您以不同的方式填充您的状态,而不是使用硬编码的对象文字。
不可能说为什么你最终会user
指向userInfo
同一个对象,因为你没有向我们展示发生这种情况的代码,但你必须做一些类似于上面代码片段的事情:
const state = {
user: userDataFromAjaxOrWhatever,
userInfo: userDataFromAjaxOrWhatever
};
反而:
const state = {
user: userDataFromAjaxOrWhatever,
userInfo: lodash.cloneDeep(userDataFromAjaxOrWhatever)
};
那么你就没有这个问题了:
const userDataFromAjaxOrWhatever = {
name: "James",
surname: "bond",
card: {
id: 7,
group: "J"
},
scope: [{ scope: "user", actions: ["create", "delete"] }]
};
const state = {
user: userDataFromAjaxOrWhatever,
userInfo: _.cloneDeep(userDataFromAjaxOrWhatever)
};
console.log(`state.user.name = ${state.user.name}`);
console.log(`state.userInfo.name = ${state.userInfo.name}`);
console.log("Setting state.user.name = Joe");
state.user.name = "Joe";
console.log(`state.user.name = ${state.user.name}`); // Joe
console.log(`state.userInfo.name = ${state.userInfo.name}`); // James
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
推荐阅读
- excel - Excel 在通过harmon.ie 打开时无法释放只读
- php - 如何使用 PHP 将 MySQL 结果嵌套到 JSON 数组中?
- java - 用域替换 IP 地址和端口
- python - Opencv 或 Numpy——有效地替换图像中的像素列表
- c - Why is the expression c=(a+b)++ not allowed in C?
- java - 如何正确初始化从输入文件读取的整数 ArrayList 的 ArrayList
- android - 下载mananger调试但崩溃
- mysql - 如何在 mysqld_safe is running 场景中设置 mysql 的密码?
- php - .htaccess 为共享主机上的多个域隐藏 .php
- node.js - 如何使用 Angular 6+ nodejs 实现 SSO