web-dev-qa-db-fra.com

React Hooks - Que se passe-t-il sous le capot?

J'ai essayé React Hooks et ils semblent simplifier des choses comme le stockage de l'état. Cependant, ils semblent faire beaucoup de choses par magie et je ne trouve pas un bon article sur comment ils fonctionnent réellement.

La première chose qui semble être magique est de savoir comment l'appel d'une fonction comme useState () provoque un nouveau rendu de votre composant fonctionnel chaque fois que vous appelez la méthode setXXX, il renvoie?

Comment quelque chose comme useEffect () simule-t-il un componentDidMount lorsque les composants fonctionnels n'ont même pas la possibilité d'exécuter du code lors du montage/démontage?

Comment useContext () obtient-il réellement l'accès au contexte et comment sait-il même quel composant l'appelle?

Et cela ne commence même pas à couvrir tous les crochets tiers qui surgissent déjà comme useDataLoader qui vous permet d'utiliser les éléments suivants ...

const { data, error, loading, retry } = useDataLoader(getData, id)

Comment les données, les erreurs, le chargement et la nouvelle tentative rendent-ils votre composant lorsqu'ils changent?

Désolé, beaucoup de questions mais je suppose que la plupart d'entre elles peuvent être résumées en une seule question, qui est:

Comment la fonction derrière le hook a-t-elle réellement accès au composant fonctionnel/sans état qui l'appelle pour qu'il puisse se souvenir des choses entre les rendus et lancer un nouveau rendu avec de nouvelles données?

20
jonhobbs

React hook utilise l'état caché d'un composant, il est stocké dans un fibre , une fibre est une entité qui correspond à l'instance du composant (au sens large, car les composants fonctionnels ne créent pas d'instances en tant que classe Composants).

C'est React renderer qui donne à un hook l'accès au contexte respectif, à l'état, etc. et accessoirement, c'est React renderer qui appelle la fonction du composant. Il peut donc associer instance de composant avec des fonctions de hook appelées à l'intérieur de la fonction de composant.

Cet extrait explique comment cela fonctionne:

let currentlyRenderedCompInstance;
const compStates = new Map(); // maps component instances to their states
const compInstances = new Map(); // maps component functions to instances

function useState(initialState) {
  if (!compStates.has(currentlyRenderedCompInstance))
    compStates.set(currentlyRenderedCompInstance, initialState);

  return [
    compStates.get(currentlyRenderedCompInstance) // state
    val => compStates.set(currentlyRenderedCompInstance, val) // state setter
  ];
}

function render(comp, props) {
  const compInstanceToken = Symbol('Renderer token for ' + comp.name);

  if (!compInstances.has(comp))
    compInstances.set(comp, new Set());

  compInstances.get(comp).add(compInstanceToken);

  currentlyRenderedCompInstance = compInstanceToken;

  return { 
    instance: compInstanceToken,
    children: comp(props)
  };
}

De la même manière que useState peut accéder au jeton d'instance de composant actuellement rendu via currentlyRenderedCompInstance, d'autres hooks intégrés peuvent également le faire et maintenir l'état de cette instance de composant.

20
Estus Flask

Il y a quelques jours à peine, Dan Abramov a créé un article sur ce sujet:

https://overreacted.io/how-does-setstate-know-what-to-do/

La seconde moitié va spécifiquement dans les détails concernant les crochets comme useState.

Pour ceux qui souhaitent approfondir certains des détails de l'implémentation, j'ai une réponse connexe ici: Comment les hooks réactifs déterminent-ils le composant auquel ils sont destinés?

6
Ryan Cogswell