【问题标题】:React js hooks lodash set strange behaviourReact js hooks lodash 设置奇怪的行为
【发布时间】:2020-02-22 09:59:48
【问题描述】:

我使用 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>
  );
}

【问题讨论】:

  • 不要依赖场外资源,请使用 Stack Snippets([&lt;&gt;] 工具栏按钮)。 Stack Snippets 支持 React,包括 JSX; here's how to do one。在现场制作您的可运行示例可以帮助人们帮助您。

标签: javascript reactjs lodash react-hooks


【解决方案1】:

问题出在哪里,当我编辑user 上的数据时,它会更改userInfo 上的相同数据,但我不明白原因。

这告诉您useruserInfo(或user.carduserInfo.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

您引用的代码不会发生这种情况,因为useruserInfo 指向不同的对象。我假设在您的真实代码中,您以不同的方式填充您的状态,而不是使用硬编码的对象文字。

不可能说为什么你最终会得到useruserInfo 指向同一个对象,因为你没有向我们展示发生这种情况的代码,但你必须做一些类似于 sn- p 高于它的位置:

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
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 谢谢你的回复,我还是没能解决问题,做进一步测试我有这个问题,我有一个功能可以将输入字段更改为一定深度@ 987654336@函数是这个const handleChangeField = field =&gt; ({target: {value}}) =&gt; { const newState = lodash.cloneDeep (state); lodash.set (newState, field, value); setState (newState); }; 你能告诉我你认为它在逻辑上是错误的吗?
  • @Paul - 假设 cloneDeep 做到了它所说的,我认为那里没有问题(除了它可能克隆的数量超出了它的需要,但这是无害的)。
猜你喜欢
  • 2020-01-05
  • 2019-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-25
  • 2012-09-30
  • 2020-04-13
相关资源
最近更新 更多