Maîtrisez le hook useImperativeHandle de React : personnalisez les refs, exposez des API de composants et créez des composants réutilisables et maintenables.
React useImperativeHandle : Personnalisation des refs et exposition d'API
Dans le paysage dynamique du développement front-end, React s'est imposé comme un outil puissant pour créer des interfaces utilisateur interactives et attrayantes. Parmi ses nombreuses fonctionnalités, le système de refs de React offre un moyen d'interagir directement avec les nœuds du DOM ou les instances de composants React. Cependant, nous avons parfois besoin de plus de contrôle sur ce qu'un composant expose au monde extérieur. C'est là qu'intervient useImperativeHandle, nous permettant de personnaliser la ref et d'exposer une API spécifique pour un usage externe. Ce guide approfondira les subtilités de useImperativeHandle, vous offrant une compréhension complète de son utilisation, de ses avantages et de ses applications pratiques pour créer des applications web mondiales robustes et maintenables.
Comprendre les refs de React
Avant de plonger dans useImperativeHandle, il est crucial de saisir les fondamentaux des refs de React. Les refs, abréviation de références, offrent un moyen d'accéder et de manipuler directement les nœuds du DOM ou les instances de composants React. Elles sont particulièrement utiles lorsque vous devez :
- Interagir avec des éléments du DOM (par exemple, donner le focus à un champ de saisie, mesurer les dimensions d'un élément).
- Appeler des méthodes sur une instance de composant.
- Gérer les intégrations de bibliothèques tierces qui nécessitent une manipulation directe du DOM.
Les refs peuvent être créées à l'aide du hook useRef. Ce hook renvoie un objet ref mutable dont la propriété .current est initialisée avec l'argument passé (null si aucun argument n'est passé). L'objet ref persiste entre les rendus, vous permettant de stocker et d'accéder à des valeurs tout au long du cycle de vie du composant.
Exemple : Utiliser useRef pour donner le focus Ă un champ de saisie :
import React, { useRef, useEffect } from 'react';
function MyInput() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return (
<input type="text" ref={inputRef} />
);
}
Dans cet exemple, inputRef est attaché à l'élément input à l'aide de la prop ref. Le hook useEffect garantit que le champ de saisie reçoit le focus lorsque le composant est monté. Cela démontre une application de base des refs pour la manipulation directe du DOM.
Le rĂ´le de useImperativeHandle
Bien que les refs donnent accès aux composants, elles peuvent exposer l'instance entière du composant, incluant potentiellement l'état interne et des méthodes qui ne devraient pas être accessibles de l'extérieur. useImperativeHandle offre un moyen de contrôler ce à quoi le composant parent a accès. Il vous permet de personnaliser l'objet ref exposé au parent, créant ainsi une API publique pour votre composant.
Voici comment fonctionne useImperativeHandle :
- Prend trois arguments : La ref Ă personnaliser, une fonction qui renvoie un objet reprĂ©sentant l'API de la ref, et un tableau de dĂ©pendances (similaire Ă
useEffect). - Personnalise la ref : La fonction que vous fournissez Ă
useImperativeHandledétermine ce que l'objet ref contiendra. Cela vous permet d'exposer sélectivement des méthodes et des propriétés, protégeant ainsi le fonctionnement interne de votre composant. - Améliore l'encapsulation : En organisant soigneusement l'API de la ref, vous améliorez l'encapsulation et rendez votre composant plus facile à maintenir et à comprendre. Les modifications de l'état interne sont moins susceptibles d'affecter l'API publique du composant.
- Permet la réutilisabilité : Une API publique bien définie facilite la réutilisation des composants dans différentes parties de votre application ou même dans des projets entièrement nouveaux.
Syntaxe :
import React, { useRef, useImperativeHandle, forwardRef } from 'react';
const MyComponent = forwardRef((props, ref) => {
const internalState = // ...
useImperativeHandle(ref, () => ({
// Méthodes et propriétés à exposer
method1: () => { /* ... */ },
property1: internalState // ou une valeur dérivée
}), [/* dépendances */]);
return (
<div> {/* ... */} </div>
);
});
Éléments clés de la syntaxe :
forwardRef: Il s'agit d'un composant d'ordre supérieur qui permet à votre composant d'accepter une ref. Il fournit le deuxième argument (ref) à la fonction de votre composant.useImperativeHandle(ref, createHandle, [deps]): C'est dans ce hook que la magie opère. Vous passez la ref fournie parforwardRef.createHandleest une fonction qui renvoie l'objet contenant l'API publique. Le tableau de dépendances ([deps]) détermine quand l'API est recréée.
Exemples pratiques de useImperativeHandle
Explorons quelques scénarios pratiques où useImperativeHandle excelle. Nous utiliserons des exemples applicables à divers publics internationaux.
1. Exposer une API publique pour un composant de modale personnalisé
Imaginez que vous construisiez un composant de modale réutilisable. Vous souhaitez permettre aux composants parents de contrôler la visibilité de la modale (afficher/masquer) et potentiellement déclencher d'autres actions. C'est un cas d'utilisation parfait pour useImperativeHandle.
import React, { forwardRef, useImperativeHandle, useState } from 'react';
const Modal = forwardRef((props, ref) => {
const [isOpen, setIsOpen] = useState(false);
const openModal = () => {
setIsOpen(true);
};
const closeModal = () => {
setIsOpen(false);
};
useImperativeHandle(ref, () => ({
open: openModal,
close: closeModal,
isOpen: isOpen, // Exposer l'état actuel
// Vous pouvez ajouter des méthodes pour l'animation ou d'autres actions ici.
}));
return (
<div style={{ display: isOpen ? 'block' : 'none' }}>
<div>Contenu de la modale</div>
<button onClick={closeModal}>Fermer</button>
</div>
);
});
export default Modal;
Explication :
- Le composant
ModalutiliseforwardRefpour recevoir une ref. - L'état
isOpengère la visibilité de la modale. - Les fonctions
openModaletcloseModalgèrent respectivement l'ouverture et la fermeture de la modale. useImperativeHandlepersonnalise la ref. Il expose les méthodesopenetclosepour contrôler la modale depuis le composant parent, ainsi que l'état `isOpen` à titre d'information.
Utilisation dans un composant parent :
import React, { useRef } from 'react';
import Modal from './Modal';
function App() {
const modalRef = useRef(null);
const handleOpenModal = () => {
modalRef.current.open();
};
const handleCloseModal = () => {
modalRef.current.close();
};
return (
<div>
<button onClick={handleOpenModal}>Ouvrir la modale</button>
<Modal ref={modalRef} />
<button onClick={handleCloseModal}>Fermer la modale (via ref)</button>
</div>
);
}
export default App;
Dans le composant parent, nous obtenons une référence à l'instance de la Modal en utilisant useRef. Nous utilisons ensuite les méthodes exposées open et close (définies dans le useImperativeHandle du composant Modal) pour contrôler la visibilité de la modale. Cela crée une API propre et contrôlée.
2. Créer un composant de saisie personnalisé avec validation
Envisagez de créer un composant de saisie personnalisé qui effectue une validation. Vous souhaitez fournir un moyen pour le composant parent de déclencher programmatiquement la validation et d'obtenir l'état de la validation.
import React, { forwardRef, useImperativeHandle, useState } from 'react';
const TextInput = forwardRef((props, ref) => {
const [value, setValue] = useState('');
const [isValid, setIsValid] = useState(true);
const validate = () => {
// Validation d'exemple (à remplacer par votre logique réelle)
const valid = value.trim().length > 0;
setIsValid(valid);
return valid; // Renvoie le résultat de la validation
};
useImperativeHandle(ref, () => ({
validate: validate,
getValue: () => value,
isValid: isValid,
}));
const handleChange = (event) => {
setValue(event.target.value);
setIsValid(true); // Réinitialiser la validité au changement
};
return (
<div>
<input type="text" value={value} onChange={handleChange} {...props} />
{!isValid && <p style={{ color: 'red' }}>Ce champ est requis.</p>}
</div>
);
});
export default TextInput;
Explication :
- Le composant
TextInpututiliseforwardRef. valuestocke la valeur de l'entrée.isValidsuit l'état de la validation.validateexécute la logique de validation (vous pouvez la personnaliser en fonction des exigences internationales ou des contraintes de saisie spécifiques). Elle renvoie un booléen représentant le résultat de la validation.useImperativeHandleexposevalidate,getValue, etisValid.handleChangemet à jour la valeur et réinitialise l'état de validation lors de la saisie de l'utilisateur.
Utilisation dans un composant parent :
import React, { useRef } from 'react';
import TextInput from './TextInput';
function Form() {
const inputRef = useRef(null);
const handleSubmit = () => {
const isValid = inputRef.current.validate();
if (isValid) {
// Traiter la soumission du formulaire
console.log('Formulaire soumis !');
} else {
console.log('La validation du formulaire a échoué.');
}
};
return (
<div>
<TextInput ref={inputRef} placeholder="Saisir du texte" />
<button onClick={handleSubmit}>Soumettre</button>
</div>
);
}
export default Form;
Le composant parent obtient la ref, appelle la méthode validate sur le composant de saisie et agit en conséquence. Cet exemple est facilement adaptable pour différents types d'entrées (par exemple, email, numéros de téléphone) avec des règles de validation plus sophistiquées. Pensez à adapter les règles de validation aux différents pays (par exemple, les formats de numéros de téléphone dans différentes régions).
3. Implémenter un composant de curseur (slider) réutilisable
Imaginez un composant de curseur où le composant parent doit définir la valeur du curseur par programmation. Vous pouvez utiliser useImperativeHandle pour exposer une méthode setValue.
import React, { forwardRef, useImperativeHandle, useState } from 'react';
const Slider = forwardRef((props, ref) => {
const [value, setValue] = useState(props.defaultValue || 0);
const handleSliderChange = (event) => {
setValue(parseInt(event.target.value, 10));
};
useImperativeHandle(ref, () => ({
setValue: (newValue) => {
setValue(newValue);
},
getValue: () => value,
}));
return (
<input
type="range"
min={props.min || 0}
max={props.max || 100}
value={value}
onChange={handleSliderChange}
/>
);
});
export default Slider;
Explication :
- Le composant
SliderutiliseforwardRef. - L'état
valuegère la valeur actuelle du curseur. handleSliderChangemet à jour la valeur lorsque l'utilisateur interagit avec le curseur.useImperativeHandleexpose une méthodesetValueet une méthode `getValue` pour un contrôle externe.
Utilisation dans un composant parent :
import React, { useRef, useEffect } from 'react';
import Slider from './Slider';
function App() {
const sliderRef = useRef(null);
useEffect(() => {
// Définir la valeur du curseur à 50 après le montage du composant
if (sliderRef.current) {
sliderRef.current.setValue(50);
}
}, []);
const handleButtonClick = () => {
// Obtenir la valeur actuelle du curseur
const currentValue = sliderRef.current.getValue();
console.log("Valeur actuelle du curseur :", currentValue);
};
return (
<div>
<Slider ref={sliderRef} min={0} max={100} defaultValue={25} />
<button onClick={handleButtonClick}>Obtenir la valeur actuelle</button>
</div>
);
}
export default App;
Le composant parent peut définir programmatiquement la valeur du curseur en utilisant sliderRef.current.setValue(50) et obtenir la valeur actuelle en utilisant `sliderRef.current.getValue()`. Cela fournit une API claire et contrôlée, et est applicable à d'autres composants graphiques. Cet exemple permet des mises à jour dynamiques à partir de données côté serveur ou d'autres sources.
Bonnes pratiques et considérations
Bien que useImperativeHandle soit un outil puissant, il est essentiel de l'utiliser judicieusement et de suivre les bonnes pratiques pour maintenir la clarté du code et prévenir les problèmes potentiels.
- Utiliser avec parcimonie : Évitez de surutiliser
useImperativeHandle. Il est mieux adapté aux scénarios où vous devez contrôler un composant depuis son parent ou exposer une API spécifique. Si possible, préférez l'utilisation de props et de gestionnaires d'événements pour communiquer entre les composants. Une utilisation excessive peut conduire à un code moins maintenable. - Définition claire de l'API : Concevez soigneusement l'API que vous exposez avec
useImperativeHandle. Choisissez des noms de méthodes et de propriétés descriptifs pour qu'il soit facile pour les autres développeurs (ou vous-même à l'avenir) de comprendre comment interagir avec le composant. Fournissez une documentation claire (par exemple, des commentaires JSDoc) si le composant fait partie d'un projet plus vaste. - Éviter la surexposition : N'exposez que ce qui est absolument nécessaire. Cacher l'état interne et les méthodes améliore l'encapsulation et réduit le risque de modifications involontaires par le composant parent. Considérez l'impact de la modification de l'état interne.
- Tableau de dépendances : Portez une attention particulière au tableau de dépendances dans
useImperativeHandle. Si l'API exposée dépend de valeurs provenant de props ou de l'état, incluez-les dans le tableau de dépendances. Cela garantit que l'API est mise à jour lorsque ces dépendances changent. L'omission de dépendances peut entraîner des valeurs obsolètes ou un comportement inattendu. - Considérer les alternatives : Dans de nombreux cas, vous pourriez obtenir le résultat souhaité en utilisant des props et des gestionnaires d'événements. Avant de vous tourner vers
useImperativeHandle, demandez-vous si les props et les gestionnaires d'événements offrent une solution plus simple. Par exemple, au lieu d'utiliser une ref pour contrôler la visibilité d'une modale, vous pourriez passer une propisOpenet un gestionnaireonCloseau composant de la modale. - Tests : Lorsque vous utilisez
useImperativeHandle, il est important de tester minutieusement l'API exposée. Assurez-vous que les méthodes et les propriétés se comportent comme prévu et qu'elles n'introduisent pas d'effets secondaires indésirables. Écrivez des tests unitaires pour vérifier le comportement correct de l'API. - Accessibilité : Lors de la conception de composants qui utilisent
useImperativeHandle, assurez-vous qu'ils sont accessibles aux utilisateurs handicapés. Cela inclut la fourniture d'attributs ARIA appropriés et la garantie que le composant est navigable au clavier. Tenez compte des normes d'internationalisation et d'accessibilité pour le public mondial. - Documentation : Documentez toujours l'API exposée dans les commentaires de votre code (par exemple, JSDoc). Décrivez chaque méthode et propriété, en expliquant son but et les paramètres qu'elle accepte. Cela aidera les autres développeurs (et votre futur vous) à comprendre comment utiliser le composant.
- Composition de composants : Envisagez de composer des composants plus petits et plus ciblés plutôt que de construire des composants monolithiques qui exposent de vastes API via
useImperativeHandle. Cette approche conduit souvent à un code plus maintenable et réutilisable.
Cas d'utilisation avancés
Au-delà des exemples de base, useImperativeHandle a des applications plus avancées :
1. Intégration avec des bibliothèques tierces
De nombreuses bibliothèques tierces (par exemple, des bibliothèques de graphiques, de cartes) nécessitent une manipulation directe du DOM ou fournissent une API que vous pouvez contrôler. useImperativeHandle peut être inestimable pour intégrer ces bibliothèques dans vos composants React.
Exemple : Intégration d'une bibliothèque de graphiques
Supposons que vous utilisiez une bibliothèque de graphiques qui vous permet de mettre à jour les données du graphique et de le redessiner. Vous pouvez utiliser useImperativeHandle pour exposer une méthode qui met à jour les données du graphique :
import React, { forwardRef, useImperativeHandle, useEffect, useRef } from 'react';
import ChartLibrary from 'chart-library'; // En supposant une bibliothèque de graphiques
const Chart = forwardRef((props, ref) => {
const chartRef = useRef(null);
useEffect(() => {
// Initialiser le graphique (à remplacer par l'initialisation réelle de la bibliothèque)
chartRef.current = new ChartLibrary(document.getElementById('chartCanvas'), props.data);
return () => {
// Nettoyer le graphique (par exemple, détruire l'instance du graphique)
if (chartRef.current) {
chartRef.current.destroy();
}
};
}, [props.data]);
useImperativeHandle(ref, () => ({
updateData: (newData) => {
// Mettre à jour les données du graphique et redessiner (à remplacer par les appels spécifiques à la bibliothèque)
if (chartRef.current) {
chartRef.current.setData(newData);
chartRef.current.redraw();
}
},
}));
return <canvas id="chartCanvas" width="400" height="300"></canvas>;
});
export default Chart;
Dans ce scénario, le composant Chart encapsule la bibliothèque de graphiques. useImperativeHandle expose une méthode updateData, permettant au composant parent de mettre à jour les données du graphique et de déclencher un nouveau dessin. Cet exemple peut nécessiter une personnalisation en fonction de la bibliothèque de graphiques spécifique que vous utilisez. N'oubliez pas de gérer le nettoyage du graphique lorsque le composant est démonté.
2. Créer des animations et des transitions personnalisées
Vous pouvez tirer parti de useImperativeHandle pour contrôler les animations et les transitions au sein d'un composant. Par exemple, vous pourriez avoir un composant qui apparaît ou disparaît en fondu. Vous pouvez exposer des méthodes pour déclencher les animations de fondu.
import React, { forwardRef, useImperativeHandle, useState, useRef, useEffect } from 'react';
const FadeInComponent = forwardRef((props, ref) => {
const [isVisible, setIsVisible] = useState(false);
const elementRef = useRef(null);
useEffect(() => {
// Optionnel : Visibilité initiale basée sur une prop
if (props.initialVisible) {
fadeIn();
}
}, [props.initialVisible]);
const fadeIn = () => {
setIsVisible(true);
};
const fadeOut = () => {
setIsVisible(false);
};
useImperativeHandle(ref, () => ({
fadeIn,
fadeOut,
}));
return (
<div
ref={elementRef}
style={{
opacity: isVisible ? 1 : 0,
transition: 'opacity 0.5s ease-in-out',
}}
>
{props.children}
</div>
);
});
export default FadeInComponent;
Explication :
FadeInComponentaccepte une ref.isVisiblegère l'état de visibilité.fadeInetfadeOutmettent à jour la visibilité.useImperativeHandleexpose les méthodesfadeInetfadeOut.- Le composant utilise des transitions CSS pour l'effet de fondu.
Utilisation dans un composant parent :
import React, { useRef } from 'react';
import FadeInComponent from './FadeInComponent';
function App() {
const fadeInRef = useRef(null);
const handleFadeIn = () => {
fadeInRef.current.fadeIn();
};
const handleFadeOut = () => {
fadeInRef.current.fadeOut();
};
return (
<div>
<FadeInComponent ref={fadeInRef} initialVisible>
<p>Ceci est le contenu en fondu.</p>
</FadeInComponent>
<button onClick={handleFadeIn}>Apparition en fondu</button>
<button onClick={handleFadeOut}>Disparition en fondu</button>
</div>
);
}
export default App;
Cet exemple crée un composant réutilisable. Le composant parent peut contrôler l'animation en utilisant les méthodes fadeIn et fadeOut exposées via la ref. Le composant parent a un contrôle total sur les comportements d'apparition et de disparition en fondu.
3. Composition de composants complexes
Lors de la création d'interfaces utilisateur complexes, vous pouvez composer plusieurs composants ensemble. useImperativeHandle peut être utilisé pour créer une API publique pour une composition de composants. Cela permet à un parent d'interagir avec le composant composite comme une seule unité.
Exemple : Composer un formulaire avec des champs de saisie
Vous pouvez créer un composant de formulaire qui contient plusieurs composants de saisie personnalisés. Vous pourriez vouloir exposer une méthode pour valider tous les champs de saisie ou obtenir leurs valeurs.
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
import TextInput from './TextInput'; // En supposant le composant TextInput d'un exemple précédent
const Form = forwardRef((props, ref) => {
const input1Ref = useRef(null);
const input2Ref = useRef(null);
const validateForm = () => {
const isValid1 = input1Ref.current.validate();
const isValid2 = input2Ref.current.validate();
return isValid1 && isValid2;
};
const getFormValues = () => ({
field1: input1Ref.current.getValue(),
field2: input2Ref.current.getValue(),
});
useImperativeHandle(ref, () => ({
validate: validateForm,
getValues: getFormValues,
}));
return (
<div>
<TextInput ref={input1Ref} placeholder="Champ 1" />
<TextInput ref={input2Ref} placeholder="Champ 2" />
</div>
);
});
export default Form;
Explication :
- Le composant
FormutiliseforwardRef. - Il utilise deux composants
TextInput(ou d'autres composants de saisie personnalisés), chacun avec sa propre ref. validateFormappelle la méthodevalidatesur chaque instance deTextInput.getFormValuesobtient les valeurs de chaque champ de saisie.useImperativeHandleexpose les méthodesvalidateetgetValues.
Cette structure est utile lorsque vous devez créer des formulaires qui ont des règles de validation complexes ou qui sont fortement personnalisés. C'est particulièrement utile si l'application doit se conformer à des règles de validation spécifiques à travers les pays et les cultures.
Considérations sur l'accessibilité et l'internationalisation
Lors de la création de composants qui utilisent useImperativeHandle, l'accessibilité et l'internationalisation sont primordiales, en particulier pour un public mondial. Considérez ce qui suit :
- Attributs ARIA : Utilisez les attributs ARIA (Accessible Rich Internet Applications) pour fournir des informations sémantiques sur vos composants aux technologies d'assistance (par exemple, les lecteurs d'écran). Assurez-vous d'un étiquetage et d'une attribution de rôles appropriés pour les éléments. Par exemple, lors de la création d'un composant de modale personnalisé, utilisez des attributs ARIA comme
aria-modal="true"etaria-labelledby. - Navigation au clavier : Assurez-vous que tous les éléments interactifs de votre composant sont accessibles au clavier. Les utilisateurs doivent pouvoir naviguer dans le composant à l'aide de la touche Tab et interagir avec les éléments en utilisant Entrée ou la barre d'espace. Portez une attention particulière à l'ordre de tabulation au sein de votre composant.
- Gestion du focus : Gérez le focus de manière appropriée, en particulier lorsque les composants deviennent visibles ou cachés. Assurez-vous que le focus est dirigé vers l'élément approprié (par exemple, le premier élément interactif d'une modale) lorsqu'un composant est ouvert et qu'il est déplacé à un endroit logique lorsque le composant est fermé.
- Internationalisation (i18n) : Concevez vos composants pour qu'ils soient facilement traduisibles dans différentes langues. Utilisez des bibliothèques d'internationalisation (par exemple,
react-i18next) pour gérer les traductions de texte et les différents formats de date, d'heure et de nombre. Évitez de coder en dur les chaînes de caractères dans vos composants et utilisez plutôt des clés de traduction. N'oubliez pas que certaines cultures lisent de gauche à droite tandis que d'autres lisent de droite à gauche. - Localisation (l10n) : Tenez compte des différences culturelles et régionales. Cela inclut des choses comme les formats de date et d'heure, les symboles monétaires, les formats d'adresse et les formats de numéro de téléphone. Vos règles de validation doivent être flexibles et adaptables aux différentes normes régionales. Pensez à la manière dont votre composant présente et traite les informations dans différentes langues.
- Contraste des couleurs : Assurez un contraste de couleur suffisant entre le texte et les éléments d'arrière-plan pour répondre aux directives d'accessibilité (par exemple, WCAG). Utilisez un vérificateur de contraste des couleurs pour vérifier que vos conceptions sont accessibles aux utilisateurs malvoyants.
- Tests avec les technologies d'assistance : Testez régulièrement vos composants avec des lecteurs d'écran et d'autres technologies d'assistance pour vous assurer qu'ils sont utilisables par les personnes handicapées. Utilisez des outils comme Lighthouse (qui fait partie des Chrome DevTools) pour auditer vos composants à la recherche de problèmes d'accessibilité.
- Support RTL : Si vous construisez une application mondiale, prenez en charge les langues de droite à gauche (RTL) comme l'arabe et l'hébreu. Cela implique plus que la simple traduction de texte. Cela nécessite d'ajuster la mise en page et la direction de vos composants. Utilisez des propriétés CSS comme
direction: rtlet réfléchissez à la manière dont vous gérerez la mise en page.
Conclusion
useImperativeHandle est un outil précieux dans l'arsenal du développeur React, permettant la personnalisation des refs et l'exposition contrôlée d'API. En comprenant ses principes et en appliquant les bonnes pratiques, vous pouvez créer des composants React plus robustes, maintenables et réutilisables. De la création de composants de modale personnalisés et de la validation de saisie à l'intégration avec des bibliothèques tierces et à la construction d'interfaces utilisateur complexes, useImperativeHandle ouvre un monde de possibilités. Cependant, il est important d'utiliser ce hook de manière réfléchie, en considérant les compromis et en explorant des approches alternatives comme les props et les événements lorsque cela est approprié. Donnez toujours la priorité à une conception d'API claire, à l'encapsulation et à l'accessibilité pour garantir que vos composants sont conviviaux et accessibles à un public mondial. En adoptant ces principes, vous pouvez créer des applications web qui offrent des expériences exceptionnelles aux utilisateurs du monde entier. Tenez toujours compte du contexte des différentes cultures et régions lors du développement de logiciels pour un public mondial.