REACT REDUX:更新深层嵌套对象中的值

IT技术 javascript json reactjs redux
2021-05-22 23:58:59

我正在尝试更新存储在深层嵌套对象中的值。它包含许多信息并且模式是固定的。我正在尝试复制对象,然后从输入返回具有更新值 onChange 的对象。但是我无法成功正确复制完整的树并返回更新的内容。

演示https : //codesandbox.io/s/4j7x8jlk9w

对象看起来像:

content: {
    label: "Label",
    templates: [
      {
        name: "example",
        type: "the type",
        items: [
          {
            key: "key1",
            properties: {
              text: {
                label: "The Label 1",
                value: "The Value 1"
              },
              color: {
                label: "Color",
                value: "#123"
              }
            }
          },
          {
            key: "key2",
            properties: {
              text: {
                label: "The Label 2",
                value: "The Value 2"
              },
              color: {
                label: "Color",
                value: "#456"
              }
            }
          }
        ]
      }
    ]
  }

减速机:

case "UPDATE_VALUE":
      const content = state.content.templates[state.templateKey].items[
        state.itemKey
      ].properties.text.value =
        action.value;

      return { ...state, content };

    default:
      return state;
  }

组件:

import React, { PureComponent } from "react";
import { connect } from "react-redux";

import { updateValue } from "./actions";

class Page extends PureComponent {
  render() {
    const { content, templateKey, itemKey } = this.props;

    return (
      <div>
        <h1
          style={{
            color:
              content.templates[templateKey].items[itemKey].properties.color
                .value
          }}
        >
          {content.templates[templateKey].items[itemKey].properties.text.value}
        </h1>
        <input
          name={content.templates[templateKey].items[itemKey].key}
          value={
            content.templates[templateKey].items[itemKey].properties.text.value
          }
          onChange={e => this.props.updateValue(e.target.name, e.target.value)}
        />
      </div>
    );
  }
}

const mapStateToProps = state => ({
  content: state.content,
  templateKey: state.templateKey,
  itemKey: state.itemKey
});

const mapDispatchToProps = dispatch => ({
  updateValue: (key, value) => dispatch(updateValue(key, value))
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Page);
3个回答

对于这样的深度嵌套数据,您可以在树的每个深度使用扩展语法,直到到达您想要更改的内容。对于数组,您可以使用它slice来创建数组的副本而不对其进行变异。

https://redux.js.org/recipes/structuringreducers/immutableupdatepatterns#correct-approach-copying-all-levels-of-nested-data

https://redux.js.org/recipes/structuringreducers/immutableupdatepatterns#inserting-and-removing-items-in-arrays

将是帮助您更好地理解这一点的资源。

让我们假设您的 reducer 获得了要更新的模板的索引,以及该模板中要更新的项目的索引。您的代码可能如下所示:

return {
    ...state,
    templates: [
      ...state.templates.slice(0, templateIndex),
      {
        ...state.templates[templateIndex],
        items: [
          ...state.templates[templateIndex].items.slice(0, itemIndex),
          {
            ...state.templates[templateIndex].items[itemIndex],
            value: action.value 
          },
          ...state.templates[templateIndex].items.slice(itemIndex)
        ]
      },
      ...state.templates.slice(templateIndex)
    ]
  }

正如您所看到的,当您像这样处理嵌套数据时,它会变得非常混乱。建议您对嵌套数据进行规范化,以使您的减速器无需做更少的工作即可找到要更改的内容。

这是您更新的代码和框:https ://codesandbox.io/s/w77yz2nzl5

您是否尝试过使用扩展操作用旧嵌套对象的当前状态的内容填充新对象,然后添加新的更新值?这样,您不更改的字段将保持不变。这并不准确,但在您的情况下我会做的是在 page.js 上创建一个方法,例如:

createNewValue = (e) => {
  const { content, templateKey, itemKey } = this.props;
  let newValues = {...content }
  newValues.templates[templateKey].items[itemKey].properties.text.value = e.target.value
  this.props.updateValue(newValues)
}

然后在您的 updateValue 操作创建器中,您只需传入新的内容对象,该对象保留您未更新的旧值,并包含您所做更改的新值。您将在 onChange 处理程序中的 page.js 上触发此方法。

首先,您没有返回正确的内容对象,因为您正在返回更新的值,因此您应该更新它:

 const content = state.content.templates[state.templateKey].items[
    state.itemKey
  ].properties.text.value =
    action.value;

和 :

  const content = state.content;
  content.templates[state.templateKey].items[
    state.itemKey
  ].properties.text.value =
    action.value;

关键是要么返回一个新的内容引用,因为您将地图状态中的选择器应用于内容本身的props(或者,作为一个更好的解决方案,将这样的减速器组合成包含多个减速器),即:

 const content = {...state.content};
  content.templates[state.templateKey].items[
    state.itemKey
  ].properties.text.value =
  action.value;

或将您的选择器应用于您想要的值(即更细粒度的选择器)