|
|
|
\begin{figure}
|
|
|
|
\begin{subfigure}[t]{\textwidth}
|
|
|
|
\begin{lstlisting}[language=JavaScript]
|
|
|
|
function useCategoryCache() {
|
|
|
|
const [cache, setCache] = React.useState<Record<string, Category>>({});
|
|
|
|
|
|
|
|
// 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}
|