\begin{figure}[H] \begin{subfigure}[t]{\textwidth} \begin{lstlisting}[language=JavaScript] function useCategoryCache() { const [cache, setCache] = React.useState>({}); // useCallback permet de retourner la même référence à la fonction // si sa closure reste inchangée. Contrairement à d'autres librairies, // React requiet qu'on passe manuellement les références présentes // dans la closure de `getCategory`, ici `cache` // (`fetchCategory` se trouve en dehors du hook) const getCategory = React.useCallback(async (id) => { if (cache[id]) return cache[id]; return fetchCategory(id).then((movie) => { setCache((cache) => ({ ...cache, [id]: movie })); return movie; }); }, [cache]); return getCategory; } const Page = (props) => { const categories = props.categories; const [fullCategories, setFullCategories] = React.useState(); const getCategory = useCategoryCache(); // useEffect éxecute le callback dès qu'une des références (aka "dépendance") // de la liste change; ici, comme appeler `getCategory` a une chance de changer // la référence à cette fonction, le useEffect est appelé plusieures fois React.useEffect(() => { const promises = categories.map((category) => getCategory(category)); Promise.all(promises).then((fullCategories) => { setFullCategories(fullCategories); }); }, [getCategory, categories]); // ... }; \end{lstlisting} \caption{Code susceptible à un bug causant les requêtes à être envoyées plusieures fois} \end{subfigure} \begin{subfigure}[t]{0.45\textwidth} \includegraphics[width=\textwidth]{fromeffectloop} \caption{Schéma des dépendances et des appels: une flèche correspond à un appel, un point à une dépendance} \end{subfigure} \hfill \begin{subfigure}[t]{0.45\textwidth} \includegraphics[width=\textwidth]{fromeffectloop2} \caption{\og Flame graph \fg abstrait des appels} \end{subfigure} \caption{Version simplifiée du bug causant plusieures requêtes à être executées} \label{fromeffectloop} \end{figure}