He leído toneladas de documentación, en todos los sitios populares, pero en ninguna parte he encontrado una respuesta. Estoy preguntando aquí para ver si me he perdido alguna documentación o un entendimiento vital.
El problema que veo es que la función mapStateToProps () de mi componente solo se llama una vez (en la inicialización). Nunca se vuelve a llamar, incluso cuando se llama al reductor. Empiezo a pensar que es porque no entiendo cómo las acciones, los reductores y los accesorios están relacionados.
Permítanme decir primero lo que yo sé:
Pero ... no he encontrado una descripción de cómo las acciones, los reductores y mapStateToProps se relacionan entre sí. Mis preguntas:
¿Ha revisado http://redux.js.org/docs/Troubleshooting.html y verificado que su caso no es uno de los problemas que describe?
Pienso en la tienda como un objeto, con propiedades que contienen datos sobre el estado de la aplicación. Esas propiedades de nivel superior pueden ser objetos que proporcionan un subárbol para contener información sobre una parte de la aplicación. ¿Es esto cierto?
Sí. La tienda contiene el objeto de estado de nivel superior internamente. Proporciona acceso a ese objeto desde store.getState()
. Ese objeto corresponde a lo que sea que devuelva del reductor de raíz y, a menudo, tiene forma de árbol.
Cuando se envía una acción a la tienda, ¿qué propiedad (o subárbol de la tienda) se actualiza? Parece que hay una creación automática de / asociación a una propiedad dentro de la tienda, pero ¿cómo se determina eso?
No, no hay creación automática de nada. La tienda simplemente comienza a señalar el resultado de llamar a su reductor de raíz.
Si su reductor de raíz es una función que escribió usted mismo, su resultado es lo que obtendrá después de enviar una acción:
function counter(state = 0, action) {
if (action.type === 'INCREMENT') {
return state + 1; // will become the next value of store.getState() after store.dispatch()
}
return state;
}
Si _genera_ el reductor de raíz con algo como combineReducers({ foo, bar })
, es lo mismo que si escribiera un reductor de raíz a mano que se ve así:
function root(state = {}, action) {
return {
foo: foo(state.foo, action),
bar: bar(state.bar, action)
}
}
Aquí es de donde a menudo provienen las propiedades en el estado. Sus valores están determinados por lo que devolvieron sus reductores foo
y bar
mientras manejaban la acción, respectivamente, por lo que nuevamente usted tiene el control total sobre ellos.
¿Cómo "sabe" mapStateToProps escuchar las actualizaciones de la propiedad / parte adecuada de la tienda? ¿Qué los une?
Pasa la función mapStateToProps
a connect()
. Genera un componente que usa store.subscribe()
para escuchar cada cambio en la tienda. Cuando la tienda ha cambiado, el componente generado lee store.getState()
y lo pasa a mapStateToProps()
para determinar los siguientes accesorios que se transmitirán. Si cambiaron, volverá a renderizar su componente con ellos.
¿Cómo podría depurar esto? ¿Qué debería hacer para descubrir por qué el envío de la acción no parece disparar mapStateToProps?
Agregue un middleware como https://github.com/theaqua/redux-logger. Verifique que el estado se actualice después de la acción de la forma esperada. Si ni siquiera se llama a mapStateToProps
, significa que
dispatch()
una acción y acaba de llamar a un creador de acciones,connect()
no se molestó en llamar a mapStateToProps()
.Ambos casos se describen en http://redux.js.org/docs/Troubleshooting.html.
En el futuro, le pedimos que primero intente hacer preguntas sobre StackOverflow y que use el rastreador de problemas cuando esté seguro de que hay un error en la biblioteca que puede reproducir de manera consistente con un ejemplo que puede compartir.
¡Gracias!
Respondiendo en orden:
{ users : {}, posts : {}, comments : {}, ui : {} }
. Consulte http://redux.js.org/docs/FAQ.html#reducers -share-state y http://redux.js.org/docs/FAQ.html#organizing -state-nested-data.combineReducers
que viene con Redux hace que sea fácil tener una función reductora específica que sea responsable de administrar las actualizaciones de un segmento de datos determinado, como: const combinedReducer = combineReducers({users : userReducer, posts : postReducer, comments : commentsReducer, ui : uiReducer});
connect()
suscribe y luego llama a mapStateToProps
del componente para ver si alguno de los datos extraídos ha cambiado desde la última vez. No hay una suscripción estatal anidada específica. Consulte http://redux.js.org/docs/FAQ.html#store -setup-subscriptions.Con suerte, eso ayuda a aclarar las cosas.
Más allá de eso, como dijo Dan: las preguntas de uso generalmente son más adecuadas para Stack Overflow. Además, la comunidad Reactiflux en Discord tiene un montón de canales de chat dedicados a las tecnologías relacionadas con React, incluido Redux, y siempre hay una cantidad de personas dispuestas a responder preguntas. Hay un enlace de invitación en https://www.reactiflux.com .
@ richb-hanover Probablemente haya sido testigo de la comparación superficial que realiza la conexión react-redux. Esto significa que los objetos anidados dentro de otros objetos no darán lugar a una nueva renderización incluso si se modifican porque solo se comprueba la clave raíz para las modificaciones.
http://redux.js.org/docs/faq/ReactRedux.html#why -isnt-my-component-re-rendering-or-my-mapstatetoprops-running
@ richb-hanover En mi caso, @gaearon detectó el problema:
O su reductor devolvió un valor referencialmente idéntico, por lo que connect () no se molestó en llamar a mapStateToProps ().
Estaba usando esta solución y este fue el código resultante
const mapStateToProps = (state, props) => {
return { id: props.id, currentState: state[props.id] };
}
const mapDispatchToProps = (dispatch) => {
return {
increment: (id) => {
dispatch({ type: 'INCREMENT', id: id })
}
}
}
const DumbListItem = ({
increment,
id,
currentState
}) => (
<div>
<li onClick={() => increment()}>{id}</li>
<span>{currentState}</span>
</div>
);
export const ConnectedListItem = connect(
mapStateToProps,
mapDispatchToProps
)(DumbListItem);
Como no pasé el parámetro id
a la llamada de incremento (ya sea como increment(id)
en la plantilla, o mediante el segundo parámetro en mapDispatchToProps
), la tienda no lo hizo actualice correctamente, así que verifique si tal vez ese sea su problema.
Comentario más útil
¿Ha revisado http://redux.js.org/docs/Troubleshooting.html y verificado que su caso no es uno de los problemas que describe?
Sí. La tienda contiene el objeto de estado de nivel superior internamente. Proporciona acceso a ese objeto desde
store.getState()
. Ese objeto corresponde a lo que sea que devuelva del reductor de raíz y, a menudo, tiene forma de árbol.No, no hay creación automática de nada. La tienda simplemente comienza a señalar el resultado de llamar a su reductor de raíz.
Si su reductor de raíz es una función que escribió usted mismo, su resultado es lo que obtendrá después de enviar una acción:
Si _genera_ el reductor de raíz con algo como
combineReducers({ foo, bar })
, es lo mismo que si escribiera un reductor de raíz a mano que se ve así:Aquí es de donde a menudo provienen las propiedades en el estado. Sus valores están determinados por lo que devolvieron sus reductores
foo
ybar
mientras manejaban la acción, respectivamente, por lo que nuevamente usted tiene el control total sobre ellos.Pasa la función
mapStateToProps
aconnect()
. Genera un componente que usastore.subscribe()
para escuchar cada cambio en la tienda. Cuando la tienda ha cambiado, el componente generado leestore.getState()
y lo pasa amapStateToProps()
para determinar los siguientes accesorios que se transmitirán. Si cambiaron, volverá a renderizar su componente con ellos.Agregue un middleware como https://github.com/theaqua/redux-logger. Verifique que el estado se actualice después de la acción de la forma esperada. Si ni siquiera se llama a
mapStateToProps
, significa quedispatch()
una acción y acaba de llamar a un creador de acciones,connect()
no se molestó en llamar amapStateToProps()
.Ambos casos se describen en http://redux.js.org/docs/Troubleshooting.html.
En el futuro, le pedimos que primero intente hacer preguntas sobre StackOverflow y que use el rastreador de problemas cuando esté seguro de que hay un error en la biblioteca que puede reproducir de manera consistente con un ejemplo que puede compartir.
¡Gracias!