【问题标题】:Nested Object mutates in React嵌套对象在 React 中发生变异
【发布时间】:2022-01-03 18:56:07
【问题描述】:

我几乎急需帮助。我是一名机械工程师,我正在为我的工作做一种计算器。我有一个问题,我花了几周的时间。我似乎无法解决它。

为了不让你厌烦冗长的代码,我会尽量概括它。

  • 我先给出一个示例代码。
  • 然后我将解释预期的行为以及实际发生的情况。
  • 最后,我将解释到目前为止我为解决此问题所做的尝试。
  • 我将根据 cmets 在底部添加更多内容,以帮助澄清我的问题。

代码示例

父对象

import {childObject} from "./childObject"

// in my code "childObject" are actually different from each other
const object1 = Object.assign({}, childObject);
const object2 = Object.assign({}, childObject);
const object3 = Object.assign({}, childObject);
const object4 = Object.assign({}, childObject);
const object5 = Object.assign({}, childObject);
const object6 = Object.assign({}, childObject);

const exampleObject = {
 name: "foo",
 otherInfo: "bar",
 nestedObject:{
  standardType: [object1, object2, object3],
  specialType: [object4, object5, object6]
 },
 sumfunc(){}
}

子对象

export const childObject = {
 name: "I'm losing my mind",
 value: "" //<-- this will change
 otherInfo: "please help me",
 sumfunc(){}
}

解释

我正在做的事情如下:

  1. 带有所有类型父对象的搜索栏。
  2. 允许用户选择一个或多个相同或不同的父对象。
  3. 将复制的选择存储在 redux 存储中。
  4. 显示选择,每个父对象作为一个表单。 [见图]
  5. 在表单中键入时,嵌套对象的值会发生变化

现在...问题是当我打开搜索栏并选择相同的 parentObject,从而复制它时,它的所有值都发生了变化。如上图所示。

我已经尝试过什么

  • 我尝试在选定的父对象上使用 lodash clone 和 deepClone。
  • 我尝试在选定的 childObjects 上使用加载克隆和 deepClone。
  • 由于对象具有相同的结构,我尝试过遍历所有键值对并浅拷贝它们。
  • 我尝试不通过搜索栏组件将 parentObject 发送到 reducer,而是只发送一个字符串,reducer 本身会将 parentObject 添加到 store。

我尝试过的所有方法都没有阻止突变。 deepClone 方法停止了突变,但作为回报,对象中的函数停止工作(也许我需要以某种方式绑定它?)

更多内容

更新nestedObject值的代码

const inputsHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
    const formCopy = Object.assign({}, formEQ);
    const inputFieldName = e.target.name;

    // if anything other than a empty, number or decimal inputted, then return
    const isNum = e.target.value.match(/^(?:\d{1,8}(?:\.\d{0,8})?)?$/);
    if (!isNum) return;
    // Update priority list to calculate the last updated input
    formCopy.priorityList = formCopy.priorityList.sort((a, b) => {
      if (a === inputFieldName) return 1;
      if (b === inputFieldName) return -1;
      else return 0;
    });
    // Update selected input field
    formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
      if (input.name === inputFieldName) {
        input.value = e.target.value;
      }
      return input;
    });

    // If more than two inputs empty do not calculate
    const emptyInputs = formCopy.inputs[calcmode].reduce(
      (acc, nV) => (nV.value === "" ? (acc += 1) : acc),
      0
    );

    // Calculate the last edited input field
    formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
      if (input.name === formCopy.priorityList[0] && emptyInputs <= 1) {
        const calculatedValue = formCopy.calculate(
          formCopy.priorityList[0],
          calcmode
        );
        input.value = Number(calculatedValue).toFixed(2);
      }
      return input;
    });

    // Final set hook, now with calculated value
    setformEQ({ ...formCopy });
  };

请 StackOverFlow 的好人...帮帮我!

【问题讨论】:

  • 您能分享一下您是如何更新对象的吗?
  • nestedObject,我看到nestedObject:{ standardType: [object1, object2, object3], specialType: [object1, object4, object5] }。您是否意识到 object1 列在 standardTypespecialType 中?另外,您是否遍历这些属性并打印出索引?您在打印时是否对每个元素应用key?你的那部分代码是什么样的。就像程序狂问的那样,你是如何更新对象的?
  • @programoholic 我已经在底部添加了。
  • @JonathonHibbard 感谢您指出错误!我没有对嵌套对象应用任何键,我应该这样做吗?我只在控制台中应用了 react 告诉我的键。
  • 你的代码很复杂..你能生成一个代码沙箱或堆栈闪电战吗?我会解决这个问题

标签: javascript reactjs redux


【解决方案1】:

您的代码几乎没有问题:

  1. 您正在根据子对象的name 属性进行过滤,并且它们都具有相同的名称。始终为对象提供唯一的id,以便轻松区分它们。

  2. 你的过滤逻辑错了:

     formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
          if (input.name === inputFieldName) {
            input.value = e.target.value; // < -- Culprit
          }
          return input;
        });
    
    

永远不要内联变异,总是创建一个新副本。

这就是你的代码 change 函数应该是这样的(为了清楚起见,我删除了动态键选择):

  const change = (e, id) => {
    const inputFieldName = e.target.name;

    // local copy of array
    const nestedArr = [...qform.nestedObject.standardType];

    // finding item to be updated
    const index = nestedArr.findIndex((i) => i.id === id);

    console.log({ index, inputFieldName, e, id });

    if (index !== -1) {
      const item = nestedArr[index];
      item.value = e.target.value;
      nestedArr[index] = item;

      // deep copy till k depth where k is the key to be updated
      const newObject = {
        ...qform,
        nestedObject: {
          ...qform.nestedObject,
          standardType: [...nestedArr],
        },
      };

      setQform(newObject);
    }}

检查此示例:Demo

【讨论】:

  • 我今天有一些时间来更改我的代码@programoholic。它不是重复的,我还没有实施你建议的解决方案。在我实施您的解决方案之前,我将保持我的问题开放。但我认为你帮助我解决了我的问题:)!
猜你喜欢
  • 2019-03-19
  • 2019-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 2018-02-08
  • 2018-10-12
  • 2021-03-29
相关资源
最近更新 更多