React / Redux / Reselect-即使看到减速器中反映的更改,mapStateToProps也会停止触发。

时间:2018-06-22 14:48:32

标签: javascript reactjs redux react-redux reselect

我搜索了类似的问题,但找不到合适的帖子(...尽管我怀疑以前曾问过这个问题),所以我事先表示歉意。

我现在已经将Redux与React一起用于几个项目,并且刚刚开始在一个学习项目中包含immutable.js和Reselect。我的测试/学习项目只是将一个大型JSON对象加载到状态中,然后使用Reselect抓取它的一部分,然后传递到我的组件中。这是我正在加载的对象的示例:

export const formState = {
  progress: {
    groupId: 3,
    questionId: 5,
  },
  content: [
    {
      group: { id: 1, name: 'Company', description: 'Data regarding your company.', questions: 2 },
      questions: [
        {
          id: 1,
          type: 'textField',
          label: 'Required *',
          inputLabelProps: { shrink: true },
          text: 'group 1 question 1',
          answer: '',
        },
    ...
    ...
    ...
    ]
  }

此对象通过在componentWillMount()中触发的动作加载到状态,然后该动作流经化简器,最终触发组件内的mapStateToProps,如下所示:

const mapStateToProps = (state) => {
   console.log(state);
   return {
     progress: getProgressData(state),
     content: getContentData(state),
   };
 };

这按预期工作。该组件有两个按钮,使您可以遍历上述“总体状态”的内容对象中的问题数组。

此外,当您按下前进或后退按钮遍历上述问题数组时,进度对象将通过操作进行更新,然后在化简器中通过以下操作进行更新:

  switch (action.type) {
    case UPDATE_PROGRESS:
      formState = state.get('formState');
      formState.progress = action.payload;
      console.log(formState);
      return state
        .set('formState', formState);     

所以这很奇怪。第一次单击前进或后退时,它起作用,并且看到对象得到更新,并且下一个问题显示在组件中。如预期的那样。

如果我单击后退或再次单击下一步,则看到动作被触发,我看到在化简器中反映了适当的状态,但是不再在mapStateToProps的console.log中看到状态。它永远不会达到那个程度。关于我做错了什么的任何想法?

注意:我似乎不只是通过以下方式更新reducer中的状态,这似乎很奇怪:     返回状态         .setIn(['formState','progress'],formState)

我最初尝试这样做,但是得到了无效的密钥路径。考虑到我正在通过fromJS()将初始状态转换为immutable.js映射,这对我来说很奇怪,因此我认为其中包含的任何内容都是映射或列表或任何适当的内容,因此可以通过这种方式寻址...无论如何,我认为一旦解决了上述问题,便会解决该问题。也就是说,除非它们相关。

一如既往,如果这是一个重复的问题,我们将不胜感激,诚挚的歉意。

谢谢!

2 个答案:

答案 0 :(得分:2)

问题

Immutable.js函数Collection.get返回给定键后面的值,在这种情况下,键是指向对象的指针。当前,您更改该对象,然后使用Collection.set将其重新设置。对象已更改,但指向该对象的指针(即您状态中存储的值)没有更改。因此,您的状态在技术上不会发生变化,并且组件也不会更新。

发生此问题的原因是您在Immutable.js集合中存储了一个普通对象。您应该只使用简单的对象,或者仅使用Immutable.js集合安全使用它。不要混在一起。

修复

选项1:Immutable.js集合

也使state.formState成为Immutable.js集合。然后通过Immutable.js方法对其进行更改。

switch (action.type) {
    case UPDATE_PROGRESS: {
      const formState = { ...state.formState };
      formState.progress = action.payload
      console.log(formState);
      return { ...state, formState };
    }

如果您决定使用Immutable.js,则应确保不要留在任何普通的javascript对象中,因为它们可以绕开Immutable.js提供的保护。

选项2:普通对象(推荐)

设置一个普通的javascript对象。

const stateCopy = { ...state };

如果您决定不使用Immutable.js,则必须注意不要意外更改状态。最简单的方法是使用传播语法复制状态:browser

答案 1 :(得分:1)

您不应该在reducer中更新状态。几乎总是会导致堰式行为immutable-update-patterns。您是否尝试过返回新对象?即

switch (action.type) {
    case UPDATE_PROGRESS:
      return {
         ...state,
         formState: {
           ...state.formState,
           progress: action.payload
         }
      };