Lors de la création d'une application React, si j'utilise le hook useSelector
, je dois respecter les règles d'appel des hooks (appelez-le uniquement à partir du niveau supérieur d'un composant fonctionnel). Si j'utilise mapStateToProps
, j'obtiens l'état dans les accessoires et je peux l'utiliser n'importe où sans aucun problème ...
Quels sont les avantages de l'utilisation du hook en plus d'économiser des lignes de code par rapport à mapStateToProps
?
3 Réponses :
Étant donné que personne ne sait comment répondre, il semble que la meilleure réponse soit que vous ne devriez PAS utiliser useselector lorsque vous avez besoin d'informations dans d'autres endroits que le niveau racine de votre composant. Puisque vous ne savez pas si le composant changera dans le futur, n'utilisez pas du tout useselector.
Si quelqu'un a une meilleure réponse que celle-ci, je changerai la réponse acceptée.
Edit: Certaines réponses ont été ajoutées, mais elles soulignent simplement pourquoi vous ne devriez pas du tout utiliser useselector, jusqu'au jour où les règles des hooks changeront, et vous pourrez également l'utiliser dans un rappel.
À partir de maintenant, il y a encore 2 réponses. Les deux dépendent juste de ma conviction que useSelector ne devrait pas être utilisé tant qu'il peut être utilisé au niveau racine comme le demandent les règles de hooks. Lorsque je ne peux ni lire ni écrire dans un rappel, à quoi ça sert?
Je pense que vous ne comprenez pas ce qu'est le «niveau supérieur». Cela signifie simplement que, à l'intérieur d'un composant fonctionnel, useSelector()
ne peut pas être placé dans des boucles, des conditions et des fonctions imbriquées. Cela n'a rien à voir avec le composant racine ou la structure des composants
import { getUsers } from 'actions/user' class MyComponent extends Component { render() { // shadowed variable getUsers, now you either rename it // or call it like this.props.getUsers // or change import to asterisk, and neither option is good const { getUsers } = this.props // ... } } const mapDispatchToProps = { getUsers, } export default connect(null, mapDispatchToProps)(MyComponent)
Si quoi que ce soit, mapStateToPtops
est situé à un niveau encore plus élevé qu'un hook call
les règles des crochets rendent très difficile l'utilisation de ce crochet spécifique. Vous devez toujours accéder d'une manière ou d'une autre à une valeur changeante à partir de l'état dans les rappels
Pour être juste, vous n'avez presque jamais à accéder à une valeur changeante dans un rappel. Je ne me souviens plus de la dernière fois que j'en avais besoin. Habituellement, si votre rappel a besoin du dernier état, vous feriez mieux de simplement distribuer une action, puis le gestionnaire de cette action (redux-thunk, redux-saga, redux-observable, etc.) accédera lui-même au dernier état
Ce ne sont que des spécificités des hooks en général (pas seulement useSelector) et il existe des tonnes de façons de le contourner si vous le souhaitez vraiment, par exemple
const MyComponent = () => { const data = useSelector(mySelector); const latestData = useRef() latestData.current = data return ( <button onClick={() => { setTimeout(() => { console.log(latestData.current) // always refers to latest data }, 5000) }} /> ) }
Quels sont les avantages de l'utilisation du hook en plus d'économiser des lignes de code par rapport à mapStateToProps?
mapStateToProps
vous travaillez) choisiriez des noms peu clairs pour les accessoires dans mapStateToProps
et vous devrez faire défiler jusqu'à mapStateToProps
dans le fichier pour savoir quel sélecteur est utilisé pour cet accessoire spécifique. Ce n'est pas le cas des hooks où les sélecteurs et les variables avec les données qu'ils renvoient sont couplés sur la même lignemapStateToProps
vous devez généralement gérer mapDispatchToProps
qui est encore plus encombrant et plus facile à perdre, en particulier en lisant le code de quelqu'un d'autre (forme objet? Forme fonction? BindActionCreators?). Prop provenant de mapDispatchToProps
peut avoir le même nom que son créateur d'action mais une signature différente car il a été remplacé dans mapDispatchToprops
. Si vous utilisez un créateur d'action dans un certain nombre de composants et que vous le renommez ensuite, ces composants continueront d'utiliser l'ancien nom provenant des accessoires. La forme de l'objet se brise facilement si vous avez un cycle de dépendance et que vous devez également gérer les noms de variables d'ombrage.
// bad const MyComponent = () => { if (condition) { // can't do this const data = useSelector(mySelector); console.log(data); } return null; } --- // good const MyComponent = () => { const data = useSelector(mySelector); if (condition) { console.log(data); // using data in condition } return null; }
Je ne sais pas à quel moment je n'avais pas besoin d'accéder aux données dans un rappel. Un bouton est enfoncé et vous devez changer les données en redux qui se produit tout le temps
L'état redux retourné par le hook useSelector
peut être transmis n'importe où ailleurs, comme c'est le cas pour mapStateToProps
. Exemple: il peut également être transmis à une autre fonction. Seule contrainte étant que les règles de hook doivent être suivies lors de sa déclaration:
Il doit être déclaré uniquement dans un composant fonctionnel.
Lors de la déclaration, il ne peut être à l'intérieur d'aucun bloc conditionnel. Exemple de code ci-dessous
export default function CustomPaginationActionsTable(props) { //Read state with useSelector. const searchCriteria = useSelector(state => { return state && state.selectedFacets; }); //use the read state in a callback invoked from useEffect hook. useEffect( ()=>{ const postParams = constructParticipantListQueryParams(searchCriteria); const options = { headers: { 'Content-Type': 'application/json' }, validateStatus: () => true }; var request = axios.post(PORTAL_SEARCH_LIST_ALL_PARTICIPANTS_URI, postParams, options) .then(function(response) { if(response.status === HTTP_STATUS_CODE_SUCCESS) { console.log('Accessing useSelector hook output in axios callback. Printing it '+JSON.stringify(searchCriteria)); } }) .catch(function(error) { }); }, []); }
EDIT: Puisque OP a posé une question spécifique - qui consiste à l'utiliser dans un rappel, je voudrais ajouter un code spécifique.En résumé, je ne vois rien qui nous empêche d'utiliser la sortie hook useSelector dans un rappel. Veuillez consulter l'exemple de code ci-dessous, c'est un extrait de mon propre code qui illustre ce cas d'utilisation particulier.
function test(displayText) { return (<div>{displayText}</div>); } export function App(props) { const displayReady = useSelector(state => { return state.readyFlag; }); const displayText = useSelector(state => { return state.displayText; }); if(displayReady) { return (<div> Outer {test(displayText)} </div>); } else { return null; } }
Et toujours lorsque vous ne pouvez pas l'utiliser à l'endroit le plus basique où vous en avez réellement besoin - dans un rappel, il est inutilisable dans des situations réelles
@YonatanNir - J'espère que cela vous aidera. J'ai mis à jour ma réponse pour le cas d'utilisation particulier qui vous intéresse. Essentiellement, l'utilisation de la sortie du hook useSelector
fonctionne également dans les fonctions de rappel.
ce n'est pas (entièrement) ce que je voulais dire. Vous décrivez un cas où vous lisez l'état au niveau racine comme les règles des hooks disent que nous devons le faire, puis utilisez cette valeur dans un rappel. Je parle de la nécessité de lire parfois les données de redux directement dans le rappel. Ecrire également les informations dans le rappel vers redux est encore un plus gros problème
Avez-vous lu ceci: react-redux.js.org/next/api/hooks#useselector
Oui et cela ne répond pas à la question des prestations
Les motivations générales des crochets ( reactjs.org/docs/hooks-intro.html#motivation )? plusieurs useSelector, plus granulaire? plus lisible 'consommant'
@xadm non, car je ne peux toujours pas utiliser l'état redux partout avec des hooks comme je le peux avec mapstatetoprops
Les deux sont des concepts pleinement valables. Cependant, pour moi personnellement, l'utilisation de crochets permet une distinction plus claire entre les accessoires provenant du composant d'un parent et ceux que le composant consomme de l'état, à l'aide d'un sélecteur.
Peut-être que vos composants sont trop complexes, nécessitent une décomposition plus profonde (dans le même fichier)? Montrez un exemple où c'est un problème
Un exemple simple serait d'essayer d'accéder à l'état d'un magasin dans une fonction de rappel ... vous ne pouvez pas faire cela avec useSelector alors que vous pouvez le faire avec l'état à l'intérieur des accessoires
Vous devriez pouvoir utiliser data / value / ref retourné par
useSelector()
dans le callback, vous ne pouvez pas appeleruseSelector()
dans un autre contexte que "render flow" des composants fonctionnels - "règles générales des hooks"C'est exactement le but ... les règles des crochets rendent très difficile l'utilisation de ce crochet spécifique. Vous devez toujours accéder d'une manière ou d'une autre à une valeur changeante à partir de l'état dans les rappels.
Étant donné que personne ne sait comment répondre, il semble que la meilleure réponse soit que vous ne devriez PAS utiliser useselector lorsque vous avez besoin d'informations dans d'autres endroits que le niveau racine de votre composant. Puisque vous ne savez pas si le composant changera à l'avenir, n'utilisez pas du tout useselector