排错

    有时,你 dispatch action 后,view 却没有更新。这是为什么呢?可能有下面几种原因。

    永远不要直接修改 reducer 的参数

    如果你想修改 Redux 给你传入的 stateaction,请住手!

    Redux 假定你永远不会修改 reducer 里传入的对象。任何时候,你都应该返回一个新的 state 对象。即使你没有使用 Immutable 这样的库,也要保证做到不修改对象。

    不变性(Immutability)可以让 高效的监听 state 的细粗度更新。它也让 redux-devtools 能提供“时间旅行”这类强大特性。

    例如,下面的 reducer 就是错误的,因为它改变了 state:

    应该重写成这样:

    1. function todos(state = [], action) {
    2. switch (action.type) {
    3. case 'ADD_TODO':
    4. // 返回新数组
    5. return [
    6. ...state,
    7. {
    8. text: action.text,
    9. completed: false
    10. }
    11. ]
    12. case 'COMPLETE_TODO':
    13. // 返回新数组
    14. return state.map((todo, index) => {
    15. if (index === action.index) {
    16. // 修改之前复制数组
    17. return Object.assign({}, todo, {
    18. completed: true
    19. })
    20. }
    21. return todo
    22. default:
    23. return state
    24. }
    25. }

    最后,如果需要更新 object,你需要使用 Underscore 提供的 _.extend 方法,或者更好的,使用 的 polyfill

    要注意 Object.assign 的使用方法。例如,在 reducer 里不要这样使用 Object.assign(state, newData),应该用 Object.assign({}, state, newData)。这样它才不会覆盖以前的 state

    你也可以通过 对象操作符 所述的使用更多简洁的语法:

    1. // 修改前:
    2. return state.map((todo, index) => {
    3. if (index === action.index) {
    4. return Object.assign({}, todo, {
    5. completed: true
    6. })
    7. }
    8. return todo
    9. })
    10. // 修改后:
    11. return state.map((todo, index) => {
    12. if (index === action.index) {
    13. return { ...todo, completed: true }
    14. }
    15. return todo
    16. })

    注意还在实验阶段的特性会经常改变。

    同时要注意那些需要复制的深层嵌套的 state 对象。而 _.extendObject.assign 只能提供浅层的 state 复制。在  章节中会教会你如何处理嵌套的 state 对象。

    不要忘记调用 dispatch(action)

    如果你定义了一个 action 创建函数,调用它并会自动 dispatch 这个 action。比如,下面的代码什么也不会做:

    TodoActions.js

    AddTodo.js

    1. import React, { Component } from 'react'
    2. import { addTodo } from './TodoActions'
    3. class AddTodo extends Component {
    4. handleClick() {
    5. // 不起作用!
    6. addTodo('Fix the issue')
    7. render() {
    8. return (
    9. <button onClick={() => this.handleClick()}>
    10. Add
    11. </button>
    12. )
    13. }
    14. }

    解法是调用 实例上的 dispatch() 方法。

    如果组件的层级非常深,把 store 一层层传下去很麻烦。因此 提供了 connect 这个 @dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750">高阶组件,它除了可以帮你监听 Redux store,还会把 dispatch 注入到组件的 props 中。

    修复后的代码是这样的:

    AddTodo.js

    1. import React, { Component } from 'react'
    2. import { connect } from 'react-redux'
    3. import { addTodo } from './TodoActions'
    4. class AddTodo extends Component {
    5. handleClick() {
    6. // 生效!
    7. this.props.dispatch(addTodo('Fix the issue'))
    8. }
    9. render() {
    10. return (
    11. <button onClick={() => this.handleClick()}>
    12. Add
    13. </button>
    14. )
    15. }
    16. }
    17. // 除了 state,`connect` 还把 `dispatch` 放到 props 里。

    如果你想的话也可以把 dispatch 手动传给其它组件。

     确保 mapStateToProps 是正确的

    你可能正确地 diaptching 一个 action 并且将它提到了 reducer 中,但是对应的 state 却没有通过 props 正确地传输。

    在 Discord 里的 redux 频道里提问,或者提交一个 issue
    如果问题终于解决了,请把解法,以便别人遇到同样问题时参考。