Puis-je utiliser React.useCallback dans un autre React.useCallback ?
P粉153503989
P粉153503989 2023-09-01 14:55:58
0
1
567
<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粉153503989
P粉153503989

répondre à tous(1)
P粉810050669

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}
      />
    );
  });
}
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal