代码之家  ›  专栏  ›  技术社区  ›  alt-rock

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

  •  0
  • alt-rock  · 技术社区  · 8 年前

    我正在尝试更新深嵌套对象中存储的值。它包含许多信息,并且模式是固定的。我试图复制对象,然后从输入返回具有更新值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 回复  |  直到 8 年前
        1
  •  4
  •   Zack Tanner    8 年前

    对于这样的深度嵌套数据,可以在树的每个深度使用spread语法,直到得到要更改的内容。对于数组,可以使用 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

        2
  •  -1
  •   futuregerald    8 年前

    您是否尝试过使用排列操作用旧嵌套对象的当前状态的内容填充新对象,然后添加新的更新值?这样,不更改的字段保持不变。这并不确切,但在您的情况下,我要做的是在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)
    }
    

        3
  •  -1
  •   Mohamad Gamal    8 年前

    首先,您没有返回正确的content对象,因为您返回的是更新的值,所以您应该更新它 :

     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;
    

    关键是返回一个新的内容引用,因为您正在将一个处于映射状态的选择器应用于内容本身的道具(或者,作为一个更好的解决方案,组合这样的reducer以包含多个reducer),即:

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

    或者对所需的值应用选择器(即更细粒度的选择器)