【问题标题】:Redux deep clone - state is always equalRedux 深度克隆 - 状态总是相等的
【发布时间】:2020-02-09 14:04:03
【问题描述】:

我在 React Redux 中有以下 reducer:

export const reducer = (state = initialStateData, action) => {
    switch (action.type) {
      case Action.TOGGLE_ARR_FILTER:
        {
          const subArr = state.jobOffers.filters[action.key];
          const filterIdx = subArr.indexOf(action.value[0]);
          const newArr = { ...state.jobOffers.filters
          };

          if (filterIdx !== -1) {
            newArr[action.key].splice(filterIdx, 1);
          } else {
            newArr[action.key].push(action.value[0]);
          }

          return {
            ...state,
            jobOffers: {
              ...state.jobOffers,
              filters: {
                ...newArr,
              },
            },
          };
        }

这是我的目标:

const initialStateData = {
  jobOffers: {
    filters: {
      employments: [],
      careerLevels: [],
      jobTypeProfiles: [],
      cities: [],
      countries: [],
    },
    configs: {
      searchTerm: '',
      currentPage: 1,
      pageSize: 5,
    },
  },
};

reducer 似乎可以正常工作,它可以正确切换值。

但是:Redux 总是显示“状态相等”,这很糟糕,因为它无法识别更改。

有人可以帮忙吗?我假设我正在返回一个新对象..

【问题讨论】:

  • 你可以试试this
  • 你已经用 splice 和 push 改变了状态,这意味着引用仍然是一样的,你必须用 silce 改变它以获得一个新的副本

标签: javascript reactjs object redux


【解决方案1】:

你可以使用 Immer ,redux 也使用它来进行嵌套内容的不可变更新。 因此,您可以编写看似“变异”状态的化简器,但实际上更新应用是不可变的。

const initialStateData = {
  jobOffers: {
    filters: {
      employments: [],
      careerLevels: [],
      jobTypeProfiles: [],
      cities: [],
      countries: [],
    },
    configs: {
      searchTerm: '',
      currentPage: 1,
      pageSize: 5,
    },
  },
};
export const reducer = immer.produce((state = initialStateData, action) => {
    switch (action.type) {
      case Action.TOGGLE_ARR_FILTER:

            const subArr = state.jobOffers.filters[action.key];
            const filterIdx = subArr.indexOf(action.value[0]);
            const newArr = state.jobOffers.filters;

            if (filterIdx !== -1) 
              newArr[action.key].splice(filterIdx, 1);
            else 
              newArr[action.key].push(action.value[0]);

            return state;
           }
          })        

【讨论】:

    【解决方案2】:

    虽然您获取了state.jobOffers.filters 的副本,但它仍然包含对原始子数组的引用,例如employments。因此,当您将 newArr[action.key]splicepush 进行变异时,Redux 不会看到这种变化,因为它仍然是相同的数组引用。

    你可以替换这个:

    if (filterIdx !== -1) {
      newArr[action.key].splice(filterIdx, 1);
    } else {
      newArr[action.key].push(action.value[0]);
    }
    

    与:

    newArr[action.key] = filterIdx !== -1 
        ? [...newArr[action.key].slice(0, filterIdx), ...newArr[action.key].slice(filterIdx+1)]
        : [...newArr[action.key], action.value[0]]);
    

    顺便说一句,您不必再次复制newArr ,因为它已经是filters 的副本。您可以替换:

    filters: {
        ...newArr,
    },
    

    只是:

    filters: newArr,
    

    【讨论】:

      猜你喜欢
      • 2018-02-07
      • 1970-01-01
      • 2019-03-19
      • 1970-01-01
      • 2017-09-01
      • 2010-09-09
      • 1970-01-01
      相关资源
      最近更新 更多