【问题标题】:React & Reselect selector claims state is the same after update更新后 React & Reselect 选择器声明状态相同
【发布时间】:2019-02-10 05:43:30
【问题描述】:

我正在我的项目中实现 Reselect,但对如何正确使用它有点困惑。在学习了有关如何使用重新选择的多个教程和文章之后,我使用了相同的模式,但仍然无法按预期工作。

我的选择器:

const getBaseInfo = (state) => state.Info;
const getResources = (state) => state.Resources;

export const ASelector = createSelector(
  [getBaseInfo, getResources],
  (items, resources) => { 
    let result = {};
    for(const item in items) {
      console.log(item);
      result[item] = _.pick(items[item], ['Title', 'Type', 'Beginning', 'minAmount', 'Address'])
    }
    for(const item in resources) {
      console.log(item);
      result[item] = {...result[item], firstImage: resources[item].firstImage}
    }
    return result;
  }
);

mapStateToProps 组件:

function mapStateToProps(state) {
  console.log(state);
  return { 
    gridInfo: ASelector(state)
  }
}

现在我的初始状态是:

state = { Info: {}, Resources: {} }

我的减速机:

const Info = ArrayToDictionary.Info(action.payload.data.Info);
  const Resources = ArrayToDictionary.Resources(action.payload.data.Info);
  let resourcesKeys = Object.keys(Resources);
  let infoKeys = Object.keys(Info);
  let temp = { ...state };
  let newInfo;

  for (let item of infoKeys) {
    newInfo = {
      Title: Info[item].Title,
      Type: Info[item].Type,
      BeginningOfInvesting: Info[item].BeginningOfInvesting,
      DateOfEstablishment: Info[item].DateOfEstablishment,
      pricePerUnit: Info[item].PricePerUnit,
      minUnits: Info[item].MinUnits,
      publicAmount: Info[item].PublicAmount,
      minInvestmentAmount: Info[item].MinInvestmentAmount,
      EinNumber: Info[item].EinNumber,
      Address: Info[item].Address,
      Status: Info[item].Status,
      Lat: Info[item].Lat,
      Lng: Info[item].Lng,
      CurrencySymbol: Info[item].CurrencySymbol,
      Publicity: Info[item].Publicity
    }
    temp.Info[item] = { ...temp.Info[item], ...newInfo }
  }
  for (let item of resourcesKeys) {
    temp.Resources[item] = { ...temp.Resources[item], ...Resources[item] }
  }
  return temp;

当组件以初始状态呈现时,我有一个操作从 api 中提取数据并将其相应地保存到 reducer 中的状态中。

现在我的状态发生了变化,但是在调试了一下reselects代码后,我在比较函数中发现新旧状态是一样的。 突然间,我的“旧”状态已经填充了 newState 数据,并且由于它们变得相同,因此它当然无法进行比较。

我的选择器有什么问题吗?

我确实尝试按照文档所述使用它,但仍然无法理解如何解决我的小问题。

非常感谢您的阅读和帮助!

【问题讨论】:

  • 你可以为state.Infostate.Resources 切片发布你的reducers 吗?这听起来好像你的减速器正在改变状态,而不是不断更新。
  • @markerikson 感谢您的回复。刚加了减速机。也许你可以指出一些事情,但我正在使用 es6 传播并返回新对象。

标签: reactjs redux react-redux reselect


【解决方案1】:

看起来temp.Info[item]temp.Resources[item] 行正在改变现有状态。您制作了顶层的浅拷贝,但没有正确复制第二层。请参阅 Redux 文档中的 Immutable Update Patterns 页面,了解为什么这是一个问题以及应该采取的措施。

您可能想尝试使用immer 库来简化您的不可变更新逻辑。此外,我们新的 redux-starter-kit 库在内部使用了 Immer。

【讨论】:

  • 感谢您的回复。我已经安装了 immer,在尝试使用它时发现我的 redux-persist 库正在改变状态以添加 ._persist ,它返回异常,因为草稿不可扩展。你知道吗?
  • 阅读文章后,我可以成功地使选择器工作。但是 immer 仍然无法使用persist。
  • 我遇到了类似的问题,您的回答有所帮助。我正在使用扩展语法复制一个数组,但这是一个浅拷贝,因此当我更新它时,我正在改变状态。嗬! (这不是我第一次这样做)。 Lodash 的 cloneDeep 救了我。把这个留给其他有同样问题的人(或者我未来的自己;))
  • 使用 deepClone form lodash 肯定会工作,如果性能对应用程序不是超级关键,则可以使用它,因为克隆整个对象确实需要一些处理能力和时间,但对于正常用例,这是一个选项以防有人不理解其他概念。
  • Deep cloning is not the right answer here,因为它会导致不必要的重新渲染。此外,这是一种 hack 解决方法,就像随机输入 setTimeouts 来修复计时错误一样。请不要那样做。
猜你喜欢
  • 2019-12-05
  • 1970-01-01
  • 1970-01-01
  • 2019-02-19
  • 2015-01-09
  • 1970-01-01
  • 1970-01-01
  • 2020-11-10
  • 1970-01-01
相关资源
最近更新 更多