Spec-Zone.ru › Redux 3

Поиск и устранение неполадок

Здесь можно обсудить распространенные проблемы и их решения.
В примерах используется React, но они будут полезны и при использовании других библиотек.

Ничего не происходит при отправке действия

Иногда вы отправляете действие, но ваш вид не обновляется. Почему это происходит? Причин может быть несколько.

Никогда не изменяйте аргументы редьюсера

Искушение изменить state или action, переданные вам Redux, велико. Не делайте этого!

Redux предполагает, что вы никогда не изменяете объекты, которые он предоставляет в редьюсере. В каждый раз вы должны возвращать новый объект состояния. Даже если вы не используете библиотеку, такую как Immutable, следует полностью избегать мутаций.

Неизменяемость позволяет react-redux эффективно подписываться на изменения вашего состояния. Она также обеспечивает отличные возможности для разработчиков, такие как путешествие во времени с помощью redux-devtools.

Например, такой редьюсер неправильный, так как он изменяет состояние:

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
  }
}

Его нужно переписать так:

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, для написания неизменяемых преобразований с лаконичной синтаксической конструкцией:

// 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
    }
  }
})

Наконец, для обновления объектов вам понадобится что-то вроде _.extend из Underscore, или лучше, полифил для Object.assign.

Убедитесь, что вы используете Object.assign правильно. Например, вместо возврата чего-то вроде Object.assign(state, newData) из ваших редьюсеров возвращайте Object.assign({}, state, newData). Таким образом, вы не перезаписываете предыдущее state.

Вы также можете включить предложение об операторе расширения объектов для более лаконичного синтаксиса:

// 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
})

Обратите внимание, что экспериментальные языковые функции могут быть изменены.

Также следите за вложенными объектами состояния, которые необходимо глубоко скопировать. _.extend и Object.assign создают поверхностную копию состояния. См. Обновление вложенных объектов для советов по работе с вложенными объектами состояния.

Не забудьте вызвать dispatch(action)

Если вы определяете создатель действия, его вызов не автоматически отправит действие. Например, этот код ничего не сделает:

TodoActions.js

export function addTodo(text) {
  return { type: 'ADD_TODO', text }
}

AddTodo.js

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>
    )
  }
}

Это не работает, потому что ваш создатель действия — это просто функция, которая возвращает действие. Вам нужно его отправить. Мы не можем привязать ваши создатели действий к конкретному экземпляру хранилища во время определения, потому что приложения, которые рендерятся на сервере, нуждаются в отдельном хранилище Redux для каждого запроса.

Исправление заключается в вызове метода dispatch() экземпляра хранилища:

handleClick() {
  // Works! (but you need to grab store somehow)
  store.dispatch(addTodo('Fix the issue'))
}

Если вы находитесь где-то глубоко в иерархии компонентов, вручную передавать хранилище неудобно. Вот почему react-redux позволяет вам использовать connect компонент высшего порядка, который, помимо подписки на хранилище Redux, введёт dispatch в свойства вашего компонента.

Исправленный код выглядит так:

AddTodo.js

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 правильный

Возможно, вы правильно отправляете действие и применяете свой редьюсер, но соответствующее состояние не правильно преобразуется в свойства.

Что-то еще не работает

Спросите в канале #redux на Discord-сервере Reactiflux или создайте вопрос.
Если вы найдете решение, исправьте этот документ для удобства следующего пользователя с такой же проблемой.

© 2015–2017 Dan Abramov
Licensed under the MIT License.
http://redux.js.org/docs/Troubleshooting.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API