【问题标题】:React / Redux / Reselect - is mapped state to props using selectors synchronous or asynchronous?React / Redux / Reselect - 使用选择器同步还是异步将状态映射到道具?
【发布时间】:2019-12-05 03:49:53
【问题描述】:

在我们的项目中,我们使用 react-redux 和 reselect 和 redux-saga

在商店中,我有一个 selectedStageId 以及一个 stages 数组和一个基于 id 查找并返回正确阶段的记忆选择器。

这个选择器作为this.props.selectedStage 映射到我的一个组件道具,并且在我的一个onClick 处理程序中,我调度了一个操作以将selectedStageId 更新为新选择的UI 项的ID,然后尝试将新的selectedStage 传递给编辑方法...

但是,即使我添加了断点并验证了我的减速器和选择器都使用新的 id 调用,新的 selectedStage 值并没有在我的组件的 props 上同步更新...而是 this.props.selectedStage 仍然引用之前的值...

示例:

onItemSelect = (stageId: number): void => {

  // updateSelectedStageId() is a mapped dispatch method that updates
  // selectedStageId in the store

  this.props.updateSelectedStageId(stageId);

  // I have debugged the above dispatched action and verified that
  // both the reducer and selector are being called with the new
  // stageId, and the selector is executing and returning the correct
  // new stage object before the next line is processed...

  this.editStage(this.props.selectedStage;); // <-- wrong value

  // this.props.selectedStage is the mapped memoized selector that
  // returns the target stage based on the selectedStageId, but
  // here it still references the previous value, not the new one
}

我读过 redux 通常是同步的,但是 redux-saga 可能会以某种方式使这个异步......但是,由于我已经验证了 reducer 和 selector 都是同步调用的,所以问题似乎是位于其他地方,可能在 connect 实际将映射状态更新为 props 时...

谁能提供一些关于如何以正确方式完成此任务的见解?

谢谢!

乔什

更新

这是我的减速器和选择器的相关位...

reducer.ts

import produce from 'immer';

const initialState = {
  selectedStageId: -1,
  stages: []
}

export const appReducer = (state = initialState, action) => {
  return produce(state, (draftState) => {
    switch (action.type) {
      case ActionType.UpdateSelectedStageId
        draftState.selectedStageId = action.id;
        break;
    }
  });
}

selectors.ts

import { createSelector } from 'reselect';

const _getSelectedStage = (stages, id) => {
  return stages.find((s) => s.id === id);
};
export const selectedStage = createSelector(
  [getStages, getSelectedStageId],
  _getSelectedStage
);

【问题讨论】:

  • 即使 redux 在理想情况下是同步的,React 仍然总是以异步方式更新组件(并提供新的 props)。
  • 那么有没有办法,类似于setState 来等待或提供回调,以便在新状态传播回道具后继续执行?
  • 您可以在componentDidUpdate 中检查props 的更改(无论他们的发起者),或者在随后调用的不同redux 操作中移动相关逻辑
  • 听起来你的减速器可能处于变异状态。对于这个动作,你的 reducer 代码是什么样的?

标签: reactjs redux react-redux redux-saga reselect


【解决方案1】:

我遇到了同样的问题(实际上几乎相同)today。

每个状态的变化(redux 与否)都是异步的。您实际上无法相信该值会被更新。

触发同步操作并不意味着它在当前渲染阶段是同步的。因此,您的应用调度操作,完成渲染,然后新的 redux 状态触发重新渲染。

dispatch({type: CHANGE_VALUE, value : newValue})
console.log(value) //oldValue

状态获取是同步更新的,但 React 只会在下一次渲染时知道该变化。

所以,只需使用您正在调度操作的值:

onItemSelect = (stageId: number): void => {

  this.props.updateSelectedStageId(stageId);

  this.editStage(stageId)

}

【讨论】:

  • 但我不关心重新渲染...我只想访问新的选择器值,它正​​在同步设置...有没有办法直接得到这个?
  • 新值只会在下一次渲染中可用
  • 那么我该如何解决这个问题呢?还没有传递阶段数组并在我的方法中手动找到正确的阶段(我认为哪种违背了记忆选择器的目的......)?
  • 我要么 A:按照这个答案的规定去做,然后立即使用 stageId,要么 B:如果你的 reducer 正在对你更新的值进行计算,请将代码添加到你的生命周期方法中以查找更新到this.props.selectedStage,然后运行this.editStage()。
  • 我是说 React 不会取消一个渲染来启动另一个。在您发送操作时,状态已更新。但是这个变化会触发另一个渲染,这个有更新的值
猜你喜欢
  • 2017-11-07
  • 2019-01-17
  • 1970-01-01
  • 1970-01-01
  • 2016-09-22
  • 2016-12-03
  • 1970-01-01
  • 2019-02-10
  • 1970-01-01
相关资源
最近更新 更多