11
votes

Dois-je utiliser useselector au lieu de mapStateToProps

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 ?


10 commentaires

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 appeler useSelector() 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


3 Réponses :


2
votes

É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.


1 commentaires

À 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?



1
votes

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?

  1. Vous gagnez du temps en n'écrivant pas la fonction de connexion chaque fois que vous avez besoin d'accéder au magasin et en le supprimant lorsque vous n'avez plus besoin d'accéder au magasin. Pas de wrappers sans fin dans React devtools
  2. Vous avez une distinction claire et aucun conflit entre les accessoires provenant de connect, les accessoires provenant du parent et les accessoires injectés par des wrappers de bibliothèques tierces
  3. Parfois, vous (ou d'autres développeurs avec 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 ligne
  4. En utilisant des hooks, vous bénéficiez des avantages généraux des hooks, dont le plus important est de pouvoir coupler et réutiliser la logique avec état associée dans plusieurs composants.
  5. Avec mapStateToProps 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;
}


1 commentaires

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



0
votes

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:

  1. Il doit être déclaré uniquement dans un composant fonctionnel.

  2. 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;
        }
    }


3 commentaires

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