REACT REDUX: обновить значение в глубоко вложенном объекте - PullRequest
0 голосов
/ 22 сентября 2018

Я пытаюсь обновить значение, хранящееся в глубоко вложенном объекте.Он содержит много информации и схема является фиксированной.Я пытаюсь скопировать объект, а затем вернуть объект со значением обновления onChange из входа.Однако я не могу успешно правильно скопировать полное дерево и вернуть обновленный контент.

DEMO : 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 ]

0 голосов
/ 22 сентября 2018

Прежде всего, вы не возвращаете правильный объект содержимого, так как вы возвращаете значение обновления, поэтому вы должны обновить это:

 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;

Ключ будет либо возвращать новую ссылку на контент, так как вы применяете селектор в состоянии карты для поддержки самого контента (или, как гораздо лучшее решение, составлять такой редуктор, чтобы содержать несколько редукторов), то есть:

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

или применение вашего селектора к нужным значениям (т. Е. Более детализированные селекторы)

0 голосов
/ 22 сентября 2018

С такими глубоко вложенными данными вы можете использовать синтаксис распространения на каждой глубине дерева, пока не достигнете того, что хотите изменить.Для массивов вы можете использовать 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

будут ресурсами, которые помогут вам лучше это понять.

Предположим, что вашему редуктору присвоен индекс длякакой шаблон для обновления и индекс для какого элемента обновлять в этом шаблоне.Ваш код может выглядеть следующим образом:

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

0 голосов
/ 22 сентября 2018

Вы пытались использовать операцию распространения для заполнения нового объекта содержимым текущего состояния старого вложенного объекта, затем добавляете новые обновленные значения?Таким образом, поля, которые вы не меняете, остаются прежними.Это не точно, но в вашем случае я бы создал метод для 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 вы просто передаете новый объект содержимого, который сохраняетстарые значения, которые вы не обновляете, и включает новое значение для изменения, которое вы делаете.Вы должны отключить этот метод на page.js в вашем обработчике onChange.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...