Redux: mapStateToProps()没有被调用

创建于 2016-05-13  ·  4评论  ·  资料来源: reduxjs/redux

在所有流行的网站上,我都阅读了大量的文档,但是却找不到答案。 我在这里问我是否错过了一些文档,或者是至关重要的理解。

我看到的问题是,组件的mapStateToProps()函数仅被调用一次(在初始化时)。 即使调用了reducer,也再也不会调用它。 我开始认为这是因为我不了解如何将动作/还原器/道具捆绑在一起。

让我先说一句我知道的事情:

  • 我知道操作描述了对该商店一部分(属性)的更新。
  • 我了解每个减速器都负责更新商店的切片/部分。 (而且我绝对明白,reducer必须为其切片返回一个新对象。)
  • 我了解到mapStateToProps从存储中“提取”某些数据,并将其作为props传递给指定的组件。

但是...我还没有找到有关动作,reduce和mapStateToProps如何相互关联的描述。 我的问题:

  • 我认为商店是一个对象,其属性包含有关应用程序状态的数据。 这些顶级属性可以是提供子树的对象,这些子树用于保存有关应用程序一部分的信息。 这是真的?
  • 将操作分派到商店时,将更新什么属性(或商店的子树)? 似乎在商店中会自动创建/关联属性,但是如何确定呢?
  • mapStateToProps如何“知道”侦听对商店的适当属性/部分的更新? 是什么将它们联系在一起?
  • 我该如何调试? 我需要做些什么才能弄清楚为什么调度动作似乎没有触发mapStateToProps?
  • 还是我在想这一切错...?
question

最有用的评论

您是否浏览过http://redux.js.org/docs/Troubleshooting.html并验证您的案件不是它描述的问题之一?

我认为商店是一个对象,其属性包含有关应用程序状态的数据。 这些顶级属性可以是提供子树的对象,这些子树用于保存有关应用程序一部分的信息。 这是真的?

是的 Store在内部保存顶级状态对象。 它提供了从store.getState()到该对象的访问。 该对象与您从根缩减器返回的内容相对应,并且通常类似于树。

将操作分派到商店时,将更新什么属性(或商店的子树)? 似乎在商店中会自动创建/关联属性,但是如何确定呢?

不,没有任何自动创建的东西。 商店只是开始指向调用根减速器的结果。

如果您的root reducer是您自己编写的函数,则其结果将是在分派操作后得到的结果:

function counter(state = 0, action) {
  if (action.type === 'INCREMENT') {
    return state + 1; // will become the next value of store.getState() after store.dispatch()
  }
  return state;
}

如果您使用combineReducers({ foo, bar })类的根减速器来生成,则与您手动编写一个如下所示的根减速器相同:

function root(state = {}, action) {
  return {
    foo: foo(state.foo, action),
    bar: bar(state.bar, action)
  }
}

这是状态属性经常来自的地方。 它们的值分别取决于foobar减速器在处理操作时返回的值,因此,您又可以完全控制它们。

mapStateToProps如何“知道”侦听对商店的适当属性/部分的更新? 是什么将它们联系在一起?

您将mapStateToProps传递给connect()函数。 它生成一个组件,该组件使用store.subscribe()来监听对商店的每次更改。 商店更改后,生成的组件将读取store.getState()并将其传递给mapStateToProps()以确定下一个要传递的道具。 如果它们更改了,它将与它们一起重新渲染您的组件。

我该如何调试? 我需要做些什么才能弄清楚为什么调度动作似乎没有触发mapStateToProps?

添加类似https://github.com/theaqua/redux-logger的中间件mapStateToProps甚至都没有被呼叫,则意味着

  • 您要么忘记了dispatch()一个动作,而是一个动作创建者,
  • 或者您的化算器返回的参考值相同,因此connect()不必费心调用mapStateToProps()

这两种情况都在http://redux.js.org/docs/Troubleshooting.html中进行了描述

将来,我们要求您首先尝试在StackOverflow上提问,并在确信库中存在可以通过示例共享的一致错误时,使用问题跟踪器。

谢谢!

所有4条评论

您是否浏览过http://redux.js.org/docs/Troubleshooting.html并验证您的案件不是它描述的问题之一?

我认为商店是一个对象,其属性包含有关应用程序状态的数据。 这些顶级属性可以是提供子树的对象,这些子树用于保存有关应用程序一部分的信息。 这是真的?

是的 Store在内部保存顶级状态对象。 它提供了从store.getState()到该对象的访问。 该对象与您从根缩减器返回的内容相对应,并且通常类似于树。

将操作分派到商店时,将更新什么属性(或商店的子树)? 似乎在商店中会自动创建/关联属性,但是如何确定呢?

不,没有任何自动创建的东西。 商店只是开始指向调用根减速器的结果。

如果您的root reducer是您自己编写的函数,则其结果将是在分派操作后得到的结果:

function counter(state = 0, action) {
  if (action.type === 'INCREMENT') {
    return state + 1; // will become the next value of store.getState() after store.dispatch()
  }
  return state;
}

如果您使用combineReducers({ foo, bar })类的根减速器来生成,则与您手动编写一个如下所示的根减速器相同:

function root(state = {}, action) {
  return {
    foo: foo(state.foo, action),
    bar: bar(state.bar, action)
  }
}

这是状态属性经常来自的地方。 它们的值分别取决于foobar减速器在处理操作时返回的值,因此,您又可以完全控制它们。

mapStateToProps如何“知道”侦听对商店的适当属性/部分的更新? 是什么将它们联系在一起?

您将mapStateToProps传递给connect()函数。 它生成一个组件,该组件使用store.subscribe()来监听对商店的每次更改。 商店更改后,生成的组件将读取store.getState()并将其传递给mapStateToProps()以确定下一个要传递的道具。 如果它们更改了,它将与它们一起重新渲染您的组件。

我该如何调试? 我需要做些什么才能弄清楚为什么调度动作似乎没有触发mapStateToProps?

添加类似https://github.com/theaqua/redux-logger的中间件mapStateToProps甚至都没有被呼叫,则意味着

  • 您要么忘记了dispatch()一个动作,而是一个动作创建者,
  • 或者您的化算器返回的参考值相同,因此connect()不必费心调用mapStateToProps()

这两种情况都在http://redux.js.org/docs/Troubleshooting.html中进行了描述

将来,我们要求您首先尝试在StackOverflow上提问,并在确信库中存在可以通过示例共享的一致错误时,使用问题跟踪器。

谢谢!

依次回答:

  • Redux通常假定状态树的顶部是普通的Javascript对象(尽管使用Immutable.js库提供的数据类型也是很常见的)。 您放置在该对象中的内容以及内容的结构完全取决于您自己。 最常见的方法是按域组织事物。 例如,假设的博客应用的状态树可能看起来像: { users : {}, posts : {}, comments : {}, ui : {} } 。 请参阅http://redux.js.org/docs/FAQ.html#reducers -share-state和http://redux.js.org/docs/FAQ.html#organizing -state-nested-data。
  • 从技术上讲,当您创建商店时,您将定义一个“ reducer”功能。 该函数将通过当前状态和传入操作进行调用,并负责以不可变的方式(具有无直接就地编辑的功能-应当更新的所有内容均应通过_all_适当的更新)返回新的状态对象。通过制作副本,对其进行修改,然后返回副本以及更新嵌套字段来完成,这也意味着要复制并更新其所有祖先。 但是,由于将更新逻辑的最后每一位都放入一个庞大的函数中是一个坏主意,因此,更新逻辑几乎总是被分解为较小的可重用子归约器函数。 构造逻辑的方式再次由您决定,但是什么都不会自动更新-这取决于您的reducer逻辑。 Redux附带的combineReducers实用工具使拥有特定的reducer功能变得容易,该功能负责管理对给定数据片段的更新,例如: const combinedReducer = combineReducers({users : userReducer, posts : postReducer, comments : commentsReducer, ui : uiReducer});
  • 只要在商店中运行_any_操作,Redux就会通知所有订阅者。 订阅React Redux connect()函数,然后调用组件的mapStateToProps以查看自上次以来提取的数据是否已更改。 没有特定的嵌套状态订阅。 请参阅http://redux.js.org/docs/FAQ.html#store -setup-subscriptions。
  • 组件未更新的第一大原因是减速器中状态的直接突变。 请参阅http://redux.js.org/docs/FAQ.html#react -not-rerendering。 除此之外,还有许多插件可用于调试和记录操作。 我在https://github.com/markerikson/redux-ecosystem-links/blob/master/devtools.md列出了很多

希望这有助于清理问题。

除此之外,正如Dan所说:使用问题通常更适合Stack Overflow。 另外,Discord上的Reactiflux社区有很多专门针对React相关技术的聊天频道,包括Redux,并且总是有很多人愿意回答问题。 https://www.reactiflux.com上有一个邀请链接。

@ richb-hanover您可能已经见证了由react-redux连接执行的浅表比较。 这意味着嵌套在其他对象中的对象即使修改了它们也不会导致重新渲染,因为只检查了根键是否有修改。

http://redux.js.org/docs/faq/ReactRedux.html#why -isnt-my-component-re-rendering-or-my-mapstatetoprops-running

@ richb-hanover就我而言,@ gaearon检测到此问题:

或者您的化简返回了相同的参考值,因此connect()不必费心调用mapStateToProps()。

我正在使用此修复程序,这是结果代码

const mapStateToProps = (state, props) => {
    return { id: props.id, currentState: state[props.id] };
}

const mapDispatchToProps = (dispatch) => {
    return {
        increment: (id) => {
            dispatch({ type: 'INCREMENT', id: id })
        }
    }
}

const DumbListItem = ({
    increment,
    id,
    currentState
}) => (
        <div>
            <li onClick={() => increment()}>{id}</li>
            <span>{currentState}</span>
        </div>
    );

export const ConnectedListItem = connect(
    mapStateToProps,
    mapDispatchToProps
)(DumbListItem);

由于我没有将id参数传递给增量调用(作为模板中的increment(id)或通过mapDispatchToProps的第二个参数),因此商店没有请正确更新,因此请检查是否可能是您的问题。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

captbaritone picture captbaritone  ·  3评论

jbri7357 picture jbri7357  ·  3评论

mickeyreiss-visor picture mickeyreiss-visor  ·  3评论

cloudfroster picture cloudfroster  ·  3评论

elado picture elado  ·  3评论