Maison  >  Questions et réponses  >  le corps du texte

Puis-je utiliser React.useCallback dans un autre React.useCallback ?

<p>有一个渲染用户卡片的组件</p> <p> <pre class="brush:js;toolbar:false;">importer React depuis "react" ; const User = React.memo(function({id, name, isSelected, ...other}) { retour ( <div {...autre}> {nom} - {isSelected && "Choisi"} </div> ); }); exporter l'utilisateur par défaut ;</pre> </p> <p>以及渲染用户卡的父组件</p> <p> <pre class="brush:js;toolbar:false;">importer React depuis "react" ; fonction Application() { const [utilisateurs, setUsers] = React.useState([ {identifiant : 1, nom : "John Doe #1"}, {identifiant : 2, nom : "John Doe #2"}, {identifiant : 3, nom : "John Doe #3"} ]); const [selectedUserId, setSelectedUserId] = React.useState(null); retourner utilisateurs.map((utilisateur) => { const isSelected = selectedUserId === user.id; retour ( <Utilisateur {...utilisateur} clé={user.id} isSelected={isSelected} onClick={() => setSelectedUserId(user.id)} /> ); }); } exporter l'application par défaut ;</pre> </p> <p>任务是« 选择用户后避免重新渲染其他用户卡 »</p> <p>我尝试使用 <code>React.useCallback</code> 钩子,这是我的第一个实现</p> <p> <pre class="brush:js;toolbar:false;">importer React depuis "react" ; const User = React.memo(function({id, name, isSelected, ...other}) { retour ( <div {...autre}> {nom} - {isSelected && "Choisi"} </div> ); }); fonction Application() { const [utilisateurs, setUsers] = React.useState([ {identifiant : 1, nom : "John Doe #1"}, {identifiant : 2, nom : "John Doe #2"}, {identifiant : 3, nom : "John Doe #3"} ]); const [selectedUserId, setSelectedUserId] = React.useState(null); const handleSelectUser = React.useCallback((userId) => () => { setSelectedUserId(userId); }, []); retourner utilisateurs.map((utilisateur) => { const isSelected = selectedUserId === user.id; retour ( <Utilisateur {...utilisateur} clé={user.id} isSelected={isSelected} onClick={handleSelectUser(user.id)} /> ); }); } exporter l'application par défaut ;</pre> </p> <p>Dans ce cas, <code>React.useCallback</code> renvoie une fonction anonyme</p> <p><strong>Résultat : toutes les cartes utilisateur sont toujours restituées après chaque clic</strong></p> <p>J'ai décidé d'envelopper cette fonction anonyme dans <code>React.useCallback</code></p> <p> <pre class="brush:js;toolbar:false;">importer React depuis "react" ; const User = React.memo(function({id, name, isSelected, ...other}) { retour ( <div {...autre}> {nom} - {isSelected && </div> ); }); fonction Application() { const [utilisateurs, setUsers] = React.useState([ {identifiant : 1, nom : "John Doe #1"}, {identifiant : 2, nom : "John Doe #2"}, {identifiant : 3, nom : "John Doe #3"} ]); const [selectedUserId, setSelectedUserId] = React.useState(null); const handleSelectUser = React.useCallback((userId) => { return React.useCallback(() => { setSelectedUserId(userId); }, []); }, []); retourner utilisateurs.map((utilisateur) => { const isSelected = selectedUserId === user.id; retour ( <Utilisateur {...utilisateur} clé={user.id} isSelected={isSelected} onClick={handleSelectUser(user.id)} /> ); }); } exporter l'application par défaut ;</pre> </p> <p>Le problème est résolu, mais il reste une question : ai-je bien fait ? L'équipe React dit : <em>N'appelez pas de Hooks à l'intérieur de boucles, de conditions ou de fonctions imbriquées</em> Quels effets secondaires vais-je obtenir ? </p> <p>Remarque: ne touchez pas le <code>user</code>component</p>
P粉153503989P粉153503989387 Il y a quelques jours518

répondre à tous(1)je répondrai

  • P粉810050669

    P粉8100506692023-09-02 12:43:37

    Expliquez pourquoi un hook ne peut pas être appelé depuis l'intérieur d'un hook (et attendez-vous à ce qu'il fonctionne de manière cohérente et fiable)

    Pourquoi vous ne pouvez pas appeler des hooks à l'intérieur d'un hook - allez ici pour une plongée très approfondie avec plus de contexte que ce dont j'ai besoin de fournir dans cette réponse https://overreacted.io/why-do-hooks-rely-on -call -commander/

    Votre solution fonctionne car malgré le fait de "enfreindre les règles", l'ordre des appels aux hooks est toujours le même... jusqu'à ce que l'utilisateur soit ajouté ou supprimé de l'état.

    Vous pouvez certainement utiliser la solution que vous avez écrite. Mais que se passe-t-il si vous devez modifier le nombre d'utilisateurs ?


    Non, vous ne pouvez pas utiliser de crochets à l’intérieur des crochets. Cela pourrait « fonctionner », mais React vous dit que cela ne fonctionne pas de manière fiable et que vous le faites mal. Le hook doit être appelé au niveau supérieur du composant de niveau supérieur du hook personnalisé.

    Vous êtes dans la bonne direction, mais la solution au problème est

    1. Utilisez les paramètres fournis à la fonction de rappel comme source de l'élément cliqué ET
    2. Si vous ne pouvez pas modifier le composant User, vous devez fournir quelques données sur l'élément div pour vous indiquer sur quel élément utilisateur a été cliqué.

    Cela ressemble à ceci :

    function Application() {
      const [users, setUsers] = React.useState([
        { id: 1, name: 'John Doe #1' },
        { id: 2, name: 'John Doe #2' },
        { id: 3, name: 'John Doe #3' },
      ]);
      const [selectedUserId, setSelectedUserId] = React.useState(null);
    
      // this callback is referentially stable - it doesn't change between renders because it has no dependencies
      const handleSelectUser = React.useCallback((e) => {
        setSelectedUserId(+e.target.getAttribute('data-userid'));
      }, []);
    
      return users.map((user) => {
        const isSelected = selectedUserId === user.id;
    
        return (
          <User
            {...user}
            data-userid={user.id} <- this line
            key={user.id}
            isSelected={isSelected}
            onClick={handleSelectUser}
          />
        );
      });
    }

    répondre
    0
  • Annulerrépondre