React Redux
Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →
Preguntas Frecuentes de Redux: React Redux
¿Por qué debería usar React-Redux?
Redux es una biblioteca independiente que puede usarse con cualquier capa de UI o framework, incluidos React, Angular, Vue, Ember y vanilla JS. Aunque Redux y React se usan comúnmente juntos, son independientes entre sí.
Cuando usas Redux con cualquier framework de UI, normalmente emplearás una biblioteca de "vinculación de UI" para conectar Redux con tu framework, en lugar de interactuar directamente con el store desde tu código de UI.
React-Redux es la biblioteca oficial de vinculación de UI de Redux para React. Si usas Redux y React juntos, deberías usar también React-Redux para conectar ambas bibliotecas.
Aunque es posible escribir manualmente la lógica de suscripción al store de Redux, esto se volvería muy repetitivo. Además, optimizar el rendimiento de la UI requeriría lógica compleja.
El proceso de suscribirse al store, verificar datos actualizados y activar un nuevo renderizado puede hacerse más genérico y reutilizable. Una biblioteca de vinculación de UI como React-Redux maneja la lógica de interacción con el store, evitando que tengas que escribir ese código tú mismo.
En general, React-Redux fomenta una buena arquitectura React e implementa optimizaciones de rendimiento complejas por ti. Además, se mantiene actualizado con los últimos cambios de API de Redux y React.
Información adicional
Documentación
¿Por qué no se vuelve a renderizar mi componente o no se ejecuta mapStateToProps?
Modificar accidentalmente tu estado directamente es con diferencia la razón más común por la que los componentes no se vuelven a renderizar tras despachar una acción. Redux espera que tus reducers actualicen el estado de forma "inmutable", lo que significa crear siempre copias de tus datos y aplicar los cambios a las copias. Si devuelves el mismo objeto desde un reducer, Redux asume que nada ha cambiado, incluso si alteraste su contenido. Del mismo modo, React Redux mejora el rendimiento mediante verificaciones superficiales de igualdad por referencia en las props entrantes en shouldComponentUpdate, y si todas las referencias son idénticas, shouldComponentUpdate devuelve false para omitir la actualización del componente.
Es crucial recordar que al actualizar un valor anidado, debes devolver también nuevas copias de todo lo superior en tu árbol de estado. Si tienes state.a.b.c.d y quieres actualizar d, necesitarás devolver nuevas copias de c, b, a y state. Este diagrama de mutación de árbol de estado muestra cómo un cambio profundo requiere modificaciones en todos los niveles superiores.
Nota que "actualizar datos inmutables" no significa que debas usar Immer, aunque es una opción válida. Puedes hacer actualizaciones inmutables en objetos y arrays de JS mediante varios enfoques:
-
Copiar objetos con funciones como
Object.assign()o_.extend(), y funciones de arrays comoslice()yconcat() -
El operador de propagación de arrays de ES2015 y el operador de propagación de objetos similar de ES2018
-
Bibliotecas de utilidades que encapsulan la lógica de actualización inmutable en funciones más simples
Más información
Documentación
-
Usando Redux: Estructuración de Reducers - Conceptos previos
-
Usando Redux: Estructuración de Reducers - Patrones de actualización inmutable
Artículos
Debates
-
React Redux #235: Función de predicado para actualizar componentes
-
React Redux #291: ¿Debería llamarse a mapStateToProps cada vez que se envía una acción?
-
Stack Overflow: ¿Forma más limpia/corta de actualizar estado anidado en Redux?
¿Por qué mi componente se vuelve a renderizar con demasiada frecuencia?
React Redux implementa varias optimizaciones para garantizar que tu componente solo se vuelva a renderizar cuando sea realmente necesario. Una de ellas es una comprobación de igualdad superficial en el objeto de props combinado generado por los argumentos mapStateToProps y mapDispatchToProps pasados a connect. Desafortunadamente, la igualdad superficial no ayuda cuando se crean nuevas instancias de arrays u objetos cada vez que se llama a mapStateToProps. Un ejemplo típico sería mapear un array de IDs y devolver las referencias de objetos correspondientes, como:
const mapStateToProps = state => {
return {
objects: state.objectIds.map(id => state.objects[id])
}
}
Aunque el array podría contener exactamente las mismas referencias de objetos cada vez, el array en sí es una referencia diferente, por lo que la comprobación de igualdad superficial falla y React Redux volvería a renderizar el componente envuelto.
Los renderizados adicionales podrían resolverse guardando el array de objetos en el estado usando un reducer, almacenando en caché el array mapeado mediante Reselect, o implementando manualmente shouldComponentUpdate en el componente con una comparación más profunda de props usando funciones como _.isEqual. ¡Ten cuidado de no hacer que tu shouldComponentUpdate() personalizado sea más costoso que el propio renderizado! Usa siempre un perfilador para verificar tus suposiciones sobre rendimiento.
Para componentes no conectados, conviene verificar qué props se están pasando. Un problema común es que un componente padre vuelva a enlazar un callback dentro de su función de renderizado, como <Child onClick={this.handleClick.bind(this)} />. Esto crea una nueva referencia de función cada vez que el padre se vuelve a renderizar. Es una buena práctica enlazar los callbacks solo una vez en el constructor del componente padre.
Más información
Documentación
Artículos
Debates
Bibliotecas
¿Cómo puedo acelerar mi mapStateToProps?
Aunque React Redux minimiza las veces que se ejecuta mapStateToProps, es recomendable asegurarse de que mapStateToProps se ejecute rápidamente y también minimice la cantidad de trabajo que realiza. El enfoque habitual es usar funciones selectoras memoizadas con Reselect. Estos selectores pueden combinarse y solo se ejecutan si sus entradas cambian, optimizando operaciones como filtrado o ordenación.
Más información
Documentación
Artículos
Debates
¿Por qué no tengo this.props.dispatch disponible en mi componente conectado?
La función connect() recibe dos argumentos principales, ambos opcionales. El primero, mapStateToProps, es una función que proporcionas para obtener datos del store cuando cambian, y pasar esos valores como props a tu componente. El segundo, mapDispatchToProps, es una función que proporcionas para utilizar la función dispatch del store, generalmente creando versiones pre-enlazadas de creadores de acciones que enviarán sus acciones automáticamente al ser llamados.
Si no proporcionas tu propia función mapDispatchToProps al llamar a connect(), React Redux proporcionará una versión predeterminada que simplemente devuelve la función dispatch como prop. Esto significa que si sí proporcionas tu propia función, dispatch no se proporciona automáticamente. Si aún quieres que esté disponible como prop, debes devolverla explícitamente tú mismo en tu implementación de mapDispatchToProps.
Más información
Documentación
Debates
-
React Redux #89: ¿Puedo agrupar varios actionCreators en una prop?
-
React Redux #255: this.props.dispatch es undefined con mapDispatchToProps
-
Stack Overflow: Cómo obtener dispatch desde this.props usando connect
¿Debo conectar solo el componente superior o puedo conectar varios?
Las primeras guías de Redux sugerían conectar pocos componentes superiores, pero esto hacía que estos conocieran demasiados requisitos de datos descendientes. La práctica actual recomienda categorizar componentes como "presentacionales" o "contenedores", conectando donde sea necesario.
La mejor práctica sugerida actualmente es categorizar tus componentes como "presentacionales" (presentational) o "contenedores" (container), y extraer un componente contenedor conectado siempre que tenga sentido:
Enfatizar "un componente contenedor arriba" fue un error. No lo tomes como norma. Mantén componentes presentacionales separados. Crea contenedores al conectarlos cuando convenga. Si duplicas código en padres para proveer datos a hijos similares, extrae un contenedor. Si un padre sabe demasiado sobre datos/acciones de sus hijos, es momento de extraer un contenedor.
De hecho, los benchmarks muestran que más componentes conectados suelen ofrecer mejor rendimiento que menos.
En general, intenta encontrar un equilibrio entre un flujo de datos comprensible y las áreas de responsabilidad de tus componentes.
Más información
Documentación
Artículos
Debates
¿Cómo se compara Redux con la API de Context de React?
Similitudes
Tanto Redux como la API de Context de React abordan el "prop drilling". Ambos permiten pasar datos sin necesidad de propagar las props a través de múltiples capas de componentes. Internamente, Redux utiliza la API de Context de React para pasar el store a lo largo de tu árbol de componentes.
Diferencias
Con Redux, obtienes el poder de las Redux DevTools Extension. Registra automáticamente cada acción que realiza tu aplicación y permite viajar en el tiempo: puedes hacer clic en cualquier acción pasada y saltar a ese momento. Redux también admite middleware, donde puedes vincular funciones personalizadas en cada despacho de acción. Ejemplos incluyen un registrador automático de eventos, intercepción de ciertas acciones, etc.
Con la API de Context de React, trabajas con un par de componentes que solo se comunican entre sí. Esto proporciona un buen aislamiento entre datos irrelevantes. También tienes flexibilidad en cómo usas los datos con tus componentes: puedes proporcionar el estado de un componente padre y pasar datos de contexto como props a componentes envueltos.
Hay una diferencia clave en cómo Redux y el Context de React tratan los datos. Redux mantiene los datos de toda tu aplicación en un objeto gigante con estado. Deduce los cambios ejecutando la función reductora que proporcionas y devuelve el siguiente estado correspondiente a cada acción despachada. React Redux luego optimiza el renderizado de componentes y asegura que cada componente solo se vuelva a renderizar cuando cambian los datos que necesita. Context, por otro lado, no mantiene ningún estado. Es solo un conducto para los datos. Para expresar cambios en los datos, debes depender del estado de un componente padre.