首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

故障排除(Troubleshooting)

这是一个分享共同问题和解决方案的地方。

这些例子使用了 React ,但是如果你使用其他的东西,你仍然应该发现它们很有用。

我发送一个动作时没有任何反应

有时,您正在尝试分派操作,但您的视图不会更新。为什么会这样?可能有几个原因。

永远不要改变reducer参数

Redux 很容易修改传给你的stateaction。请不要这样做!

Redux 假定你永远不会改变它在 reducer 中给你的对象。每一次,你都必须返回新的状态对象。即使你不使用像 Immutable 这样的库,你也需要完全避免突变。

不变性是让 react-redux 有效地订阅你的状态的细粒度更新。它还具有出色的开发人员体验功能,例如使用 redux-devtools 进行时间旅行。

例如,像这样的 reducer 是错误的,因为它会改变状态:

代码语言:javascript
复制
function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      // Wrong! This mutates state
      state.push({
        text: action.text,
        completed: false
      })
      return state
    case 'COMPLETE_TODO':
      // Wrong! This mutates state[action.index].
      state[action.index].completed = true
      return state
    default:
      return state
  }
}

它需要像这样重写:

代码语言:javascript
复制
function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      // Return a new array
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case 'COMPLETE_TODO':
      // Return a new array
      return state.map((todo, index) => {
        if (index === action.index) {
          // Copy the object before mutating
          return Object.assign({}, todo, {
            completed: true
          })
        }
        return todo
      })
    default:
      return state
  }
}

这是更多的代码,但这正是Redux可预测和高效的原因。如果你想要更少的代码,你可以使用一个助手,像React.addons.update一个简洁的语法来编写不可变的转换:

代码语言:javascript
复制
// Before:
return state.map((todo, index) => {
  if (index === action.index) {
    return Object.assign({}, todo, {
      completed: true
    })
  }
  return todo
})

// After
return update(state, {
  [action.index]: {
    completed: {
      $set: true
    }
  }
})

最后,要更新对象,您需要类似于_.extendUnderscore或更好的Object.assign填充。

确保你正确使用Object.assign。例如,不要从你的reducer 中返回类似Object.assign(state, newData)的东西,而是返回Object.assign({}, state, newData)。这样你不会覆盖以前的state

您还可以启用对象扩展运算符提议以获得更简洁的语法:

代码语言:javascript
复制
// Before:
return state.map((todo, index) => {
  if (index === action.index) {
    return Object.assign({}, todo, {
      completed: true
    })
  }
  return todo
})

// After:
return state.map((todo, index) => {
  if (index === action.index) {
    return { ...todo, completed: true }
  }
  return todo
})

请注意,实验语言功能可能会发生变化。

同时留意需要深度复制的嵌套状态对象。_.extendObject.assign做一个状态的浅拷贝。有关如何处理嵌套状态对象的建议,请参阅更新嵌套对象。

别忘了调用 dispatch(action)

如果您定义了动作创建者,调用它将不会自动发送动作。例如,这段代码什么都不执行:

TodoActions.js

代码语言:javascript
复制
export function addTodo(text) {
  return { type: 'ADD_TODO', text }
}

AddTodo.js

代码语言:javascript
复制
import React, { Component } from 'react'
import { addTodo } from './TodoActions'

class AddTodo extends Component {
  handleClick() {
    // Won't work!
    addTodo('Fix the issue')
  }

  render() {
    return (
      <button onClick={() => this.handleClick()}>
        Add
      </button>
    )
  }
}

它不起作用,因为您的动作创建者只是一个返回动作的函数。实际发送它取决于你。我们无法在定义期间将您的动作创建者绑定到特定的Store实例,因为在服务器上呈现的应用程序需要为每个请求分别提供一个Redux存储。

修复方法是在商店实例上调用dispatch()方法:

代码语言:javascript
复制
handleClick() {
  // Works! (but you need to grab store somehow)
  store.dispatch(addTodo('Fix the issue'))
}

如果您位于组件层次结构的深处,则手动传递存储会很麻烦。这就是为什么 react-redux 可以让你使用connect 高阶组件,除了订阅你的 Redux 商店之外,还可以注入dispatch组件的道具。

固定代码如下所示:

AddTodo.js

代码语言:javascript
复制
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { addTodo } from './TodoActions'

class AddTodo extends Component {
  handleClick() {
    // Works!
    this.props.dispatch(addTodo('Fix the issue'))
  }

  render() {
    return (
      <button onClick={() => this.handleClick()}>
        Add
      </button>
    )
  }
}

// In addition to the state, `connect` puts `dispatch` in our props.
export default connect()(AddTodo)

如果需要,可以手动传递dispatch给其他组件。

确保mapStateToProps正确

你可能正确地调度行动并应用你的减速器,但是相应的状态没有被正确地转换成 props 。

别的东西不起作用

询问 #redux Reactiflux Discord 频道,或者创建一个问题

如果你想出来了,编辑这个文件给下一个有同样问题的人。

扫码关注腾讯云开发者

领取腾讯云代金券

http://www.vxiaotou.com