Ir al contenido principal
Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Resolución de problemas

Este es un espacio para compartir problemas comunes y sus soluciones. Los ejemplos usan React, pero igualmente te resultarán útiles si empleas otra tecnología.

No ocurre nada cuando despacho una acción

En ocasiones, intentas despachar una acción pero tu vista no se actualiza. ¿Por qué sucede esto? Puede haber varias razones.

Nunca modifiques los argumentos del reducer

Es tentador modificar el state o action que Redux te pasa. ¡No lo hagas!

Redux asume que nunca mutarás los objetos que te proporciona en el reducer. Cada vez, sin excepción, debes devolver un nuevo objeto de estado. Incluso si no usas una biblioteca como Immer, debes evitar completamente la mutación.

La inmutabilidad es lo que permite a react-redux suscribirse eficientemente a actualizaciones granulares de tu estado. También habilita funciones de gran utilidad para desarrolladores como el viaje en el tiempo con redux-devtools.

Por ejemplo, este reducer es incorrecto porque muta el estado:

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

Debe reescribirse así:

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

Requiere más código, pero es precisamente lo que hace a Redux predecible y eficiente. Si quieres reducir código, puedes usar ayudantes como React.addons.update para escribir transformaciones inmutables con sintaxis concisa:

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

Finalmente, para actualizar objetos, necesitarás algo como _.extend de Underscore, o mejor aún, un polyfill de Object.assign.

Asegúrate de usar Object.assign correctamente. Por ejemplo, en lugar de devolver algo como Object.assign(state, newData) desde tus reducers, devuelve Object.assign({}, state, newData). Así no sobreescribirás el state anterior.

También puedes usar la propuesta del operador de propagación de objetos para una sintaxis más sucinta:

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

Ten en cuenta que las características experimentales del lenguaje pueden cambiar.

También presta atención a objetos anidados en el estado que requieran copia profunda. Tanto _.extend como Object.assign hacen copias superficiales del estado. Consulta Actualizar objetos anidados para ver sugerencias sobre cómo manejar objetos de estado anidados.

No olvides llamar a dispatch(action)

Si defines un creador de acciones, llamarlo no despachará automáticamente la acción. Por ejemplo, este código no hará nada:

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

No funciona porque tu creador de acciones es solo una función que devuelve una acción. Depende de ti despacharla realmente. No podemos vincular tus creadores de acciones a una instancia de Store específica durante la definición porque las aplicaciones que se renderizan en servidor necesitan un almacén Redux separado por cada solicitud.

La solución es llamar al método dispatch() en la instancia del almacén:

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

Si estás en lo profundo de la jerarquía de componentes, es engorroso pasar el almacén manualmente. Por eso react-redux te permite usar un componente de orden superior connect que, además de suscribirte a un almacén Redux, inyecta dispatch en las props de tu componente.

El código corregido se vería así:

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)

Luego puedes pasar dispatch manualmente a otros componentes si lo deseas.

Asegúrate de que mapStateToProps sea correcta

Es posible que estés despachando una acción correctamente y aplicando tu reducer, pero el estado correspondiente no se esté transformando adecuadamente en props.

Si algo más no funciona

Consulta en el canal de Discord #redux de Reactiflux o crea un issue.

Si resuelves el problema, edita este documento como cortesía para la siguiente persona que enfrente el mismo error.