J'ai lu des tonnes de documentation - sur tous les sites populaires - mais je n'ai trouvé nulle part de réponse. Je demande ici pour voir si j'ai manqué de la documentation ou un élément essentiel de compréhension.
Le problème que je vois est que la fonction mapStateToProps () de mon composant n'est appelée qu'une seule fois (à l'initialisation). Il n'est plus jamais appelé, même lorsque le réducteur est appelé. Je commence à penser que c'est parce que je ne comprends pas comment les actions / réducteurs / accessoires sont tous liés entre eux.
Laissez-moi d'abord dire ce que je sais:
Mais ... je n'ai pas trouvé de description de la relation entre les actions, les réducteurs et les mapStateToProps. Mes questions:
Avez-vous parcouru http://redux.js.org/docs/Troubleshooting.html et vérifié que votre cas ne fait pas partie des problèmes décrits?
Je considère le magasin comme un objet, avec des propriétés qui contiennent des données sur l'état de l'application. Ces propriétés de niveau supérieur peuvent être des objets qui fournissent une sous-arborescence pour contenir des informations sur une partie de l'application. Est-ce vrai?
Oui. Store contient l'objet d'état de niveau supérieur en interne. Il permet d'accéder à cet objet à partir de store.getState()
. Cet objet correspond à tout ce que vous retournez du réducteur de racine, et il ressemble souvent à un arbre.
Lorsqu'une action est envoyée au magasin, quelle propriété (ou sous-arborescence du magasin) est mise à jour? Il semble qu'il y ait une création / association automatique à une propriété dans le magasin, mais comment cela est-il déterminé?
Non, il n'y a pas de création automatique de quoi que ce soit. Le magasin commence juste à pointer vers le résultat de l'appel de votre réducteur racine.
Si votre réducteur de racine est une fonction que vous avez écrite vous-même, son résultat est ce que vous obtiendrez après avoir distribué une action:
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 vous _générez_ le réducteur de racine avec quelque chose comme combineReducers({ foo, bar })
, c'est la même chose que si vous aviez écrit un réducteur de racine à la main qui ressemble à ceci:
function root(state = {}, action) {
return {
foo: foo(state.foo, action),
bar: bar(state.bar, action)
}
}
C'est de là que proviennent souvent les propriétés de l'État. Leurs valeurs sont déterminées par ce que vos réducteurs foo
et bar
renvoyés lors de la gestion de l'action, respectivement, donc encore une fois, vous avez un contrôle total sur eux.
Comment mapStateToProps "sait" écouter les mises à jour de la propriété / partie appropriée du magasin? Qu'est-ce qui les unit?
Vous passez la fonction mapStateToProps
à connect()
. Il génère un composant qui utilise store.subscribe()
pour écouter chaque modification apportée au magasin. Lorsque le magasin a changé, le composant généré lit store.getState()
et le passe à mapStateToProps()
pour déterminer les prochains accessoires à transmettre. S'ils ont changé, le rendu de votre composant sera refait avec eux.
Comment pourrais-je déboguer cela? Que dois-je faire pour comprendre pourquoi la distribution de l'action ne semble pas déclencher mapStateToProps?
Ajoutez un middleware comme https://github.com/theaqua/redux-logger. Vérifiez que l'état se met à jour après l'action comme vous le souhaitez. Si mapStateToProps
n'est même pas appelé, cela signifie que
dispatch()
une action et vous venez d'appeler un créateur d'action,connect()
n'a pas pris la peine d'appeler mapStateToProps()
.Ces deux cas sont décrits dans http://redux.js.org/docs/Troubleshooting.html.
À l'avenir, nous vous demandons d'essayer d'abord de poser des questions sur StackOverflow et d'utiliser le suivi des problèmes lorsque vous êtes sûr qu'il y a un bogue dans la bibliothèque que vous pouvez reproduire de manière cohérente avec un exemple que vous pouvez partager.
Merci!
Répondre dans l'ordre:
{ users : {}, posts : {}, comments : {}, ui : {} }
. Voir http://redux.js.org/docs/FAQ.html#reducers -share-state et http://redux.js.org/docs/FAQ.html#organizing -state-nested-data.combineReducers
fourni avec Redux facilite la création d'une fonction de réduction spécifique chargée de gérer les mises à jour d'une tranche de données donnée, comme: const combinedReducer = combineReducers({users : userReducer, posts : postReducer, comments : commentsReducer, ui : uiReducer});
connect()
s'abonne, puis appelle le composant mapStateToProps
pour voir si l'une des données extraites a changé depuis la dernière fois. Il n'y a pas d'abonnement d'état imbriqué spécifique. Voir http://redux.js.org/docs/FAQ.html#store -setup-subscriptions.J'espère que cela aidera à clarifier les choses.
Au-delà de cela, comme l'a dit Dan: les questions d'utilisation sont généralement mieux adaptées à Stack Overflow. De plus, la communauté Reactiflux sur Discord dispose de nombreux canaux de discussion dédiés aux technologies liées à React, y compris Redux, et il y a toujours un certain nombre de personnes qui traînent pour répondre aux questions. Il y a un lien d'invitation sur https://www.reactiflux.com .
@ richb-hanover Vous avez probablement été témoin de la comparaison superficielle qui est effectuée par la connexion react-redux. Cela signifie que les objets imbriqués dans d'autres objets ne donneront pas lieu à un rendu même s'ils sont modifiés car seule la clé racine est vérifiée pour les modifications.
http://redux.js.org/docs/faq/ReactRedux.html#why -isnt-my-component-re-rendering-or-my-mapstatetoprops-running
@ richb-hanover Dans mon cas, @gaearon a détecté le problème:
Ou votre réducteur a renvoyé une valeur référentielle identique, donc connect () n'a pas pris la peine d'appeler mapStateToProps ().
J'utilisais ce correctif et c'était le code résultant
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);
Comme je n'ai pas passé le paramètre id
à l'appel d'incrément (soit en tant que increment(id)
dans le modèle, soit via le deuxième paramètre de mapDispatchToProps
), le magasin n'a pas mise à jour correctement, vérifiez si c'est peut-être votre problème.
Commentaire le plus utile
Avez-vous parcouru http://redux.js.org/docs/Troubleshooting.html et vérifié que votre cas ne fait pas partie des problèmes décrits?
Oui. Store contient l'objet d'état de niveau supérieur en interne. Il permet d'accéder à cet objet à partir de
store.getState()
. Cet objet correspond à tout ce que vous retournez du réducteur de racine, et il ressemble souvent à un arbre.Non, il n'y a pas de création automatique de quoi que ce soit. Le magasin commence juste à pointer vers le résultat de l'appel de votre réducteur racine.
Si votre réducteur de racine est une fonction que vous avez écrite vous-même, son résultat est ce que vous obtiendrez après avoir distribué une action:
Si vous _générez_ le réducteur de racine avec quelque chose comme
combineReducers({ foo, bar })
, c'est la même chose que si vous aviez écrit un réducteur de racine à la main qui ressemble à ceci:C'est de là que proviennent souvent les propriétés de l'État. Leurs valeurs sont déterminées par ce que vos réducteurs
foo
etbar
renvoyés lors de la gestion de l'action, respectivement, donc encore une fois, vous avez un contrôle total sur eux.Vous passez la fonction
mapStateToProps
àconnect()
. Il génère un composant qui utilisestore.subscribe()
pour écouter chaque modification apportée au magasin. Lorsque le magasin a changé, le composant généré litstore.getState()
et le passe àmapStateToProps()
pour déterminer les prochains accessoires à transmettre. S'ils ont changé, le rendu de votre composant sera refait avec eux.Ajoutez un middleware comme https://github.com/theaqua/redux-logger. Vérifiez que l'état se met à jour après l'action comme vous le souhaitez. Si
mapStateToProps
n'est même pas appelé, cela signifie quedispatch()
une action et vous venez d'appeler un créateur d'action,connect()
n'a pas pris la peine d'appelermapStateToProps()
.Ces deux cas sont décrits dans http://redux.js.org/docs/Troubleshooting.html.
À l'avenir, nous vous demandons d'essayer d'abord de poser des questions sur StackOverflow et d'utiliser le suivi des problèmes lorsque vous êtes sûr qu'il y a un bogue dans la bibliothèque que vous pouvez reproduire de manière cohérente avec un exemple que vous pouvez partager.
Merci!