Реагировать js крючки loda sh установить странное поведение - PullRequest
0 голосов
/ 22 февраля 2020

Я использую loda sh, чтобы иметь возможность изменять значение атрибута (объекта, массива) на определенную глубину, но у меня странное поведение.

Ситуация такая, я используйте реакцию js с хуками, в состоянии у меня есть объект, который содержит информацию о пользователе, поэтому я делаю выборку для загрузки информации о пользователе для объекта, который находится в состоянии, называемом user.

Однако эта информация сохраняется не только в объекте user, но и в другом объекте с именем userInfo, поэтому у меня есть эта информация, которая находится в состоянии дважды, но с другим номинативным атрибутом.

Что делать Мне нужно иметь эту информацию дважды, только для того, чтобы убедиться, что когда пользователь хочет изменить свои данные (страницу профиля), я проверю, действительно ли модифицированные им данные были изменены, то есть существует ли хотя бы один элемент, отличный от оригинал.

Проблема в том, что когда я редактирую данные, которые на user, в свою очередь, изменяет те же данные на userInfo, но я не понимаю причина.

Самое странное, что эта проблема случается со мной только на локальном проекте, в котором я работаю над простым примером для codeandbox, проблема не возникает.

Кажется, проблема в из-за функции 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>
  );
}

1 Ответ

1 голос
/ 22 февраля 2020

Проблема в том, что когда я редактирую данные, которые на user, в свою очередь, изменяет те же данные на userInfo, но я не понимаю причину.

Это говорит о том, что user и userInfo (или user.card и 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 и userInfo указывают на разные объекты. Я предполагаю, что в вашем реальном коде вы заполняете свое состояние не так, как жестко закодированные литералы объектов.

Невозможно сказать, почему вы указали 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>
...