Performance
-
Utilisez judicieusement les hooks d’optimisation de performance intégrés de React :
useMemopour les calculs coûteux.useCallbackpour les références de fonction stables.memopour empêcher les re-rendus inutiles de composants complexes.
// Bon - mémorisation d'un calcul coûteux const sortedItems = useMemo(() => { return items .slice() .sort((a, b) => b.timestamp - a.timestamp); }, [items]); // Bon - callback stable pour les composants enfants const handleSubmit = useCallback((data: FormData) => { mutate(data); }, [mutate]); -
Utilisez l’optimisation d’élément pour éviter les re-rendus inutiles. Si vous donnez à React la même référence d’élément, il ignorera le rendu du composant.
-
Utilisez la méthode d’enregistrement de cycle de vie appropriée en fonction des exigences de chargement de votre composant :
- Utilisez
getAsyncLifecyclepour les modales, les espaces de travail, les pages secondaires et les autres composants qui peuvent être chargés à la demande.
// Bon - modale chargée uniquement lorsque nécessaire export const markPatientAliveModal = getAsyncLifecycle(() => import('./mark-patient-alive.modal'), options);- Utilisez
getSyncLifecyclepour les composants déjà importés qui doivent être disponibles immédiatement, comme les liens légers, les boutons d’action et les composants racine qui ne doivent pas attendre un autre chunk :
// Bon - composant inclus dans le bundle principal export const startVisitForm = getSyncLifecycle(startVisitFormComponent, { featureName: 'start-visit-form', moduleName, });La différence clé est l’emplacement du code du composant.
getAsyncLifecycleutilise un import dynamique, ce qui permet au bundler de créer un chunk séparé qu’O3 ne charge que lorsque le composant est nécessaire.getSyncLifecycleenveloppe un composant déjà importé statiquement ; il reste donc dans le bundle principal du module frontend et est disponible dès que ce module se charge. Évitez de rendre chaque export asynchrone par défaut : beaucoup de petits chunks dynamiques peuvent ajouter des requêtes à l’exécution. Lisez-en plus sur la différence entre les métadonnées statiques et dynamiques ici. - Utilisez
-
Préférez les icônes et pictogrammes exportés par
@openmrs/esm-frameworklorsqu’un asset OpenMRS correspondant existe. Ils proviennent des sprites du styleguide O3 et évitent d’importer des icônes individuelles depuis@carbon/react/iconsquand le système de design fournit déjà l’asset. -
Envisagez d’utiliser le préchargement pour améliorer la réactivité de votre application. Le préchargement peut être particulièrement utile dans ces cas :
- Préchargement de données pour les éléments qui sont susceptibles d’être consultés ensuite :
import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework'; import { preload } from 'swr'; // Précharger la page suivante de résultats const nextPageUrl = `${restBaseUrl}/patient?startIndex=${currentPage * pageSize}&limit=${pageSize}`; const prefetchNextPage = () => { void preload(nextPageUrl, openmrsFetch); };- Préchargement de données en utilisant l’API preload de SWR lors du survol de liens ou de boutons :
import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework'; import { preload } from 'swr'; // Précharger les schémas de formulaire lors du survol de liens dans le form builder <ConfigurableLink className={styles.link} to={editSchemaUrl} templateParams={{ formUuid: form?.uuid }} onMouseEnter={() => form?.uuid && void preload(`${restBaseUrl}/form/${form.uuid}?v=full`, openmrsFetch)} > {form.name} </ConfigurableLink>N’oubliez pas que bien que le préchargement puisse améliorer l’expérience utilisateur, il doit être utilisé judicieusement pour éviter les requêtes réseau inutiles et l’utilisation de données.
-
Ajustez votre configuration SWR de manière appropriée pour optimiser les performances. O3 enveloppe les composants des modules frontend dans un
openmrsComponentDecoratorqui fournit un cache SWR partagé,openmrsFetchcomme fetcher par défaut et une configuration SWR globale qui désactive la plupart des revalidations automatiques. Parce que le composant SWRConfig fusionne les configurations du contexte parent, vous pouvez surcharger les options dans la configuration globale sur une base par composant. Alternativement, vous pouvez spécifier une configuration personnalisée au niveau de chaque hook. Chaque hook SWR accepte un objet d’options comme argument, que vous pouvez utiliser pour personnaliser le comportement du hook.// Simplifié depuis le décorateur de composant OpenMRS const defaultSwrConfig = { // nombre maximum de nouvelles tentatives après l'échec des requêtes errorRetryCount: 3, // fonction fetcher par défaut fetcher: openmrsFetch, // revalider une seule fois toutes les 30 minutes focusThrottleInterval: 1800000, revalidateIfStale: true, // désactiver les revalidations automatiques par défaut revalidateOnFocus: false, revalidateOnReconnect: false, refreshInterval: 0, shouldRetryOnError: (error) => { if (error instanceof OpenmrsFetchError) { const status = error.response.status; if (status >= 500) { return true; } if (status === 401 || status === 403 || status === 429) { return true; } return false; } return true; }, }; <SWRConfig value={defaultSwrConfig}> <ComponentContext.Provider value={this.state.config}> {opts.disableTranslations ? ( <Comp {...this.props} /> ) : ( <I18nextProvider // props omises pour la brièveté > <Comp {...this.props} /> </I18nextProvider> )} </ComponentContext.Provider> </SWRConfig>// Configuration au niveau du composant en utilisant le composant SWRConfig <SWRConfig value={{ revalidateOnFocus: true, revalidateOnReconnect: true }}> <Component /> </SWRConfig>// Configuration personnalisée au niveau de chaque hook const { data: response } = useOpenmrsSWR<PatientSearchResponse>('/ws/rest/v1/patient?v=full', { swrConfig: { revalidateOnFocus: true, revalidateOnReconnect: true, }, }); const patients = response?.data?.results ?? []; -
Évitez les pièges de performance courants :
- Ne créez pas de nouveaux objets ou tableaux dans le rendu lorsqu’ils sont passés à des enfants mémorisés.
- Évitez les définitions de fonction inline dans JSX lorsqu’elles provoquent le rerender d’enfants mémorisés.
- N’utilisez pas l’index comme clé dans les listes dont l’ordre peut changer.
- Empêchez les re-rendus inutiles avec une propriété d’état claire et des props de composant étroites.
// Mauvais - nouvelle fonction créée à chaque rendu <Button onClick={() => handleClick(id)} /> // Bon - référence de fonction stable const handleButtonClick = useCallback(() => { handleClick(id); }, [id, handleClick]); <Button onClick={handleButtonClick} /> -
Surveillez les performances de votre application en utilisant le React DevTools Profiler . Pour profiler votre application, exécutez à la fois votre application et le shell d’application O3 localement, puis utilisez le mécanisme de surcharge de carte d’import pour charger votre application dans le shell d’application O3. Ouvrez ensuite le React DevTools Profiler dans votre navigateur et démarrez une session de profilage. Les choses à surveiller incluent :
- Composants avec des re-rendus fréquents
- Composants qui sont lents à rendre
- Tâches longues dans le thread principal
- Composants qui pourraient être mémorisés