diff --git a/app/pages/docs/react/use-context/+Page.mdx b/app/pages/docs/react/use-context/+Page.mdx new file mode 100644 index 0000000..d6653cb --- /dev/null +++ b/app/pages/docs/react/use-context/+Page.mdx @@ -0,0 +1,168 @@ +--- +title: Le hook useContext de React +description: Découvrez comment utiliser le hook useContext de React pour gérer les contextes dans vos applications. +tags: [Frontend, React, JavaScript, TypeScript, Bibliothèque, Interface utilisateur (UI)] +--- + +import Callout from "@/components/Callout"; +import tabs from "./tabs"; + +Les contextes sont un moyen de diffuser des données au travers des composants, sans avoir à les passer explicitement à chaque composant. + +Pour faire simple, imaginons une arborescence de plusieurs composants imbriqués les uns dans les autres : + + + +Fastidieux, n'est-ce pas ? On transmet à chaque fois les mêmes données, et ce, à chaque niveau de l'arborescence. + +C'est là que les contextes entrent en jeu ! +On va pouvoir alors déclarer notre contexte _(qui contiendra les données à diffuser)_ et le fournir à un niveau supérieur de l'arborescence. + +## Déclaration d'un contexte + +Avant de penser à notre contexte, on va réfléchir à ce que l'on veut diffuser et les valeurs par défaut. +Si on reprend notre exemple avec le thème clair et sombre, on sait que l'on va vouloir diffuser la valeur du thème et une fonction pour le changer. + +On va donc préparer le terrain en créant un fichier `ThemeContext.jsx` _(ou `ThemeContext.tsx` si tu utilises TypeScript)_ : + + + +## Fournir un contexte + +Maintenant on peut le dire : notre contexte est prêt à être utilisé ! +Il ne reste plus qu'à le fournir à notre arborescence de composants en lui créant un `Provider`. + + + Un `Provider` est un composant qui va permettre de **diffuser** les données du contexte à ses enfants. + Il est important de noter que le `Provider` doit **englober** les composants qui vont utiliser le contexte. + + +Un contexte React est un objet qui contient deux propriétés : `Provider` et `Consumer`. + +Le `Provider` est un composant qui va permettre de diffuser les données du contexte à ses enfants. +Le `Consumer` est un composant qui va permettre de récupérer les données du contexte. + + + +Mais on peut aller encore plus loin, en créant un Provider dédié à notre contexte ! +Cela permettra de simplifier l'arborescence de composants et de rendre le code plus lisible : + + + +Et pour terminer, on va maintenant pouvoir directement imbriquer notre `ThemeProvider` dans notre `App` : + + + +## Utilisation d'un contexte + +C'est bien beau de créer un contexte, mais comment l'utiliser ? +Tu te souviens peut-être du `Consumer` que l'on a évoqué plus tôt, non ? + +Et bien, il est temps de le mettre en pratique ! 😁 + +Pour commencer, nous allons avoir besoin du hook `useContext` de React. +Ce hook va nous permettre de récupérer les données du contexte, et ce, directement dans nos composants. + + + +Pas mal, non ? 😉 +Fini l'arborescence de composants à rallonge, on peut maintenant récupérer les données du contexte directement dans nos composants ! + +## Les défauts des contextes + +Seulement... Un grand pouvoir implique de grandes responsabilités. 🕷️ + +Bien que les contextes soient très pratiques, il faut prendre en compte quelques points : + +- On ne peut pas utiliser les contextes pour tout et n'importe quoi. Ils sont plutôt adaptés pour diffuser des données qui sont utilisées par plusieurs composants. +- Les contextes peuvent rendre le code plus difficile à comprendre. +- L'utilisation de nombreux contextes va faire apparaître ce qu'on appelle le **context hell**. + +### Le context hell + +Dans cet article, nous avons vu comment créer un contexte et l'utiliser. +Et par chance, nous n'avons pas encore rencontré le **context hell**. + +Mais maintenant, que se passe-t-il si on a besoin de plusieurs contextes _(plusieurs dizaines par exemple !)_ dans notre application ? +On va se retrouver avec une arborescence de composants qui va devenir de plus en plus difficile à comprendre et à maintenir. + +Et c'est ça, le **context hell**. + + + +Maintenant, demande à un développeur d'inverser le provider `UserProvider` avec le provider `NoteProvider`. +C'est jouable sans difficulté, mais si tu entends des cris de désespoir, c'est normal. 😅 + +Pour éviter de tomber dans le **context hell**, il est important de bien réfléchir à l'utilisation des contextes dans notre application avec ces quelques questions : + +- Est-ce que l'utilisation d'un contexte est vraiment nécessaire pour ce cas d'usage ? +- Est-ce que le contexte est utilisé par plusieurs composants ? +- Est-ce que le contexte est utilisé par des composants éloignés dans l'arborescence ? + +Mais alors, si tu as besoin d'autant de contextes dans ton application, comment faire ? +Et bien, il existe des solutions pour éviter le **context hell** : + +- Utiliser des bibliothèques tierces comme Redux _(solution lourde, mais très puissante)_ +- Créer un nouveau composant qui va regrouper tous les contextes _(solution plus légère, mais plus difficile à maintenir)_ + +N'étant pas un grand fan de Redux, je vais plutôt te présenter la deuxième solution. +Mais si tu veux en savoir plus sur Redux, n'hésite pas à consulter la documentation officielle ! + +### Résoudre le context hell avec un composant dédié + +Parlons de ce fameux composant qui va regrouper tous les contextes ! +On ne parle pas ici d'un simple composant Providers qui va imbriquer tous les Provider de nos contextes, mais d'une solution plus élégante. + +Après tout, nous sommes des feignants développeurs, non ? 😏 + +Réfléchissons à ce que l'on veut faire : + +- On veut pouvoir regrouper tous les contextes dans un seul composant. +- On veut pouvoir ajouter ou supprimer des contextes facilement. +- On veut pouvoir facilement les ordonner entre eux. +- On veut éviter le **context hell**. + +Et si on créait un composant Providers qui va nous permettre de faire tout ça ? + + + +Ici on ne va pas remettre une cascade de Provider comme on a pu le voir plus tôt. +On va chercher à créer une fonction qui va nous permettre de les imbriquer les uns dans les autres. + + + + + `React.cloneElement` est une fonction qui va permettre de cloner un élément React en lui passant de nouvelles propriétés. + Cela va nous permettre de créer une nouvelle arborescence de composants sans modifier l'arborescence actuelle. + + Le premier argument est l'élément à cloner _(le composant)_, et le deuxième argument est un objet contenant les nouvelles propriétés. + Le troisième argument est le contenu de l'élément cloné _(les enfants)_. + + +Et maintenant, on va pouvoir utiliser notre fonction `nest` pour imbriquer nos Provider en utilisant la méthode `reduceRight` : + + + + + `reduceRight` est une méthode qui va permettre de réduire un tableau _(ou un objet)_ en appliquant une fonction de rappel de droite à gauche. + Cela va nous permettre de réduire un tableau de `Provider` en les imbriquant les uns dans les autres sans se soucier de l'ordre _(qui est défini par le tableau)_. + + Dans l'idée, on commence par le **dernier** élément du tableau, et on l'imbrique avec l'élément **précédent** du tableau et ainsi de suite jusqu'au **premier** élément du tableau. + Chaque itération va créer un nouvel élément imbriqué dans le précédent, en appelant la fonction `nest` qui est passée en argument. + + +Et voilà ! Il ne nous reste plus qu'à utiliser notre composant `Providers` pour regrouper tous nos `Provider` : + + + +Évidemment le fichier contiendra toujours beaucoup de lignes, mais au moins, on a évité le **context hell** ! +Il sera nettement plus facile de modifier l'ordre des Provider ou d'en ajouter de nouveaux. + +## Conclusion + +Ça casse un peu la tête, mais les contextes sont un outil très puissant pour diffuser des données dans nos applications React. + +C'est aussi une excellente solution pour éviter d'utiliser des bibliothèques tierces comme Redux _(qui est très bien, mais qui peut être un peu lourd pour des petites applications)_. +On prendra d'ailleurs le temps de parler de Redux et de Zustand dans un prochain article 😉 + +Et si tu as besoin de plusieurs contextes dans ton application, n'oublie pas de réfléchir à l'utilisation de notre composant Providers pour éviter le **context hell**. diff --git a/app/pages/docs/react/use-context/page.md b/app/pages/docs/react/use-context/page.md deleted file mode 100644 index 7cb902a..0000000 --- a/app/pages/docs/react/use-context/page.md +++ /dev/null @@ -1,537 +0,0 @@ ---- -title: Le hook useContext de React -description: Découvrez comment utiliser le hook useContext de React pour gérer les contextes dans vos applications. -tags: [Frontend, React, JavaScript, TypeScript, Bibliothèque, Interface utilisateur (UI)] ---- - -Les contextes sont un moyen de diffuser des données au travers des composants, sans avoir à les passer explicitement à chaque composant. - -Pour faire simple, imaginons une arborescence de plusieurs composants imbriqués les uns dans les autres : - -{% tabs defaultSelectedTab="jsx" %} - -{% tab value="jsx" label="JSX" %} - -```jsx -import { useState } from "react"; - -const App = () => { - const [theme, setTheme] = useState("light"); - - return ; -}; - -const A = ({ theme, setTheme }) => { - return ; -}; - -const B = ({ theme, setTheme }) => { - return ; -}; -``` - -{% /tab %} - -{% tab value="tsx" label="TSX" %} - -```tsx -import type { Dispatch, SetStateAction } from "react"; - -import { useState } from "react"; - -type Theme = "light" | "dark"; - -const App = () => { - const [theme, setTheme] = useState("light"); - - return ; -}; - -const A = ({ theme, setTheme }: { theme: Theme; setTheme: Dispatch> }) => { - return ; -}; - -const B = ({ theme, setTheme }: { theme: Theme; setTheme: Dispatch> }) => { - return ; -}; -``` - -{% /tab %} - -{% /tabs %} - -Fastidieux, n'est-ce pas ? On transmet à chaque fois les mêmes données, et ce, à chaque niveau de l'arborescence. - -C'est là que les contextes entrent en jeu ! -On va pouvoir alors déclarer notre contexte _(qui contiendra les données à diffuser)_ et le fournir à un niveau supérieur de l'arborescence. - -## Déclaration d'un contexte - -Avant de penser à notre contexte, on va réfléchir à ce que l'on veut diffuser et les valeurs par défaut. -Si on reprend notre exemple avec le thème clair et sombre, on sait que l'on va vouloir diffuser la valeur du thème et une fonction pour le changer. - -On va donc préparer le terrain en créant un fichier `ThemeContext.jsx` _(ou `ThemeContext.tsx` si tu utilises TypeScript)_ : - -{% tabs defaultSelectedTab="jsx" %} - -{% tab value="jsx" label="JSX" %} - -```jsx -import { createContext } from "react"; - -// On crée notre contexte, avec une valeur par défaut : un thème clair -const ThemeContext = createContext({ - theme: "light", - setTheme: () => {}, -}); -``` - -{% /tab %} - -{% tab value="tsx" label="TSX" %} - -```tsx -import type { Dispatch, SetStateAction } from "react"; - -import { createContext } from "react"; - -// On crée un type pour les valeurs de thème -export type Theme = "light" | "dark"; - -// On crée un type pour notre contexte -type ThemeContextType = { - theme: Theme; - setTheme: Dispatch>; -}; - -// On crée notre contexte, avec une valeur par défaut : un thème clair -const ThemeContext = createContext({ - theme: "light", - setTheme: () => {}, -}); -``` - -{% /tab %} - -{% /tabs %} - -## Fournir un contexte - -Maintenant on peut le dire : notre contexte est prêt à être utilisé ! -Il ne reste plus qu'à le fournir à notre arborescence de composants en lui créant un `Provider`. - -{% callout type="question" title="Un provider ?" %} - -Un `Provider` est un composant qui va permettre de **diffuser** les données du contexte à ses enfants. -Il est important de noter que le `Provider` doit **englober** les composants qui vont utiliser le contexte. - -{% /callout %} - -Un contexte React est un objet qui contient deux propriétés : `Provider` et `Consumer`. - -Le `Provider` est un composant qui va permettre de diffuser les données du contexte à ses enfants. -Le `Consumer` est un composant qui va permettre de récupérer les données du contexte. - -{% tabs defaultSelectedTab="jsx" %} - -{% tab value="jsx" label="JSX" %} - -```jsx -import { useState } from "react"; - -const App = () => { - const [theme, setTheme] = useState("light"); - - return ( - - - - ); -}; -``` - -{% /tab %} - -{% tab value="tsx" label="TSX" %} - -```tsx -import type { Theme } from "./ThemeContext"; - -import { useState } from "react"; - -const App = () => { - const [theme, setTheme] = useState("light"); - - return ( - - - - ); -}; -``` - -{% /tab %} - -{% /tabs %} - -Mais on peut aller encore plus loin, en créant un Provider dédié à notre contexte ! -Cela permettra de simplifier l'arborescence de composants et de rendre le code plus lisible : - -{% tabs defaultSelectedTab="jsx" %} - -{% tab value="jsx" label="JSX" %} - -```jsx -import { createContext, useState } from "react"; - -const ThemeContext = createContext({ - theme: "light", - setTheme: () => {}, -}); - -const ThemeProvider = ({ children }) => { - const [theme, setTheme] = useState("light"); - - return {children}; -}; - -export { ThemeContext, ThemeProvider }; -``` - -{% /tab %} - -{% tab value="tsx" label="TSX" %} - -```tsx -import type { ReactNode } from "react"; - -import { createContext, useState } from "react"; - -export type Theme = "light" | "dark"; - -type ThemeContextType = { - theme: Theme; - setTheme: Dispatch>; -}; - -const ThemeContext = createContext({ - theme: "light", - setTheme: () => {}, -}); - -type ThemeProviderProps = { - children: ReactNode; -}; - -const ThemeProvider = ({ children }: ThemeProviderProps) => { - const [theme, setTheme] = useState("light"); - - return {children}; -}; - -export { ThemeContext, ThemeProvider }; -``` - -{% /tab %} - -{% /tabs %} - -Et pour terminer, on va maintenant pouvoir directement imbriquer notre `ThemeProvider` dans notre `App` : - -```jsx -import { ThemeProvider } from "./ThemeContext"; - -const App = () => { - return ( - - - - ); -}; -``` - -## Utilisation d'un contexte - -C'est bien beau de créer un contexte, mais comment l'utiliser ? -Tu te souviens peut-être du `Consumer` que l'on a évoqué plus tôt, non ? - -Et bien, il est temps de le mettre en pratique ! 😁 - -Pour commencer, nous allons avoir besoin du hook `useContext` de React. -Ce hook va nous permettre de récupérer les données du contexte, et ce, directement dans nos composants. - -```jsx -import { ThemeContext } from "./ThemeContext"; -import { useContext } from "react"; - -const C = () => { - const { theme, setTheme } = useContext(ThemeContext); - - return <>{/** JSX */}; -}; -``` - -Pas mal, non ? 😉 -Fini l'arborescence de composants à rallonge, on peut maintenant récupérer les données du contexte directement dans nos composants ! - -## Les défauts des contextes - -Seulement... Un grand pouvoir implique de grandes responsabilités. 🕷️ - -Bien que les contextes soient très pratiques, il faut prendre en compte quelques points : - -- On ne peut pas utiliser les contextes pour tout et n'importe quoi. Ils sont plutôt adaptés pour diffuser des données qui sont utilisées par plusieurs composants. -- Les contextes peuvent rendre le code plus difficile à comprendre. -- L'utilisation de nombreux contextes va faire apparaître ce qu'on appelle le **context hell**. - -### Le context hell - -Dans cet article, nous avons vu comment créer un contexte et l'utiliser. -Et par chance, nous n'avons pas encore rencontré le **context hell**. - -Mais maintenant, que se passe-t-il si on a besoin de plusieurs contextes _(plusieurs dizaines par exemple !)_ dans notre application ? -On va se retrouver avec une arborescence de composants qui va devenir de plus en plus difficile à comprendre et à maintenir. - -Et c'est ça, le **context hell**. - -```jsx -root.render( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - , -); -``` - -Maintenant, demande à un développeur d'inverser le provider `UserProvider` avec le provider `NoteProvider`. -C'est jouable sans difficulté, mais si tu entends des cris de désespoir, c'est normal. 😅 - -Pour éviter de tomber dans le **context hell**, il est important de bien réfléchir à l'utilisation des contextes dans notre application avec ces quelques questions : - -- Est-ce que l'utilisation d'un contexte est vraiment nécessaire pour ce cas d'usage ? -- Est-ce que le contexte est utilisé par plusieurs composants ? -- Est-ce que le contexte est utilisé par des composants éloignés dans l'arborescence ? - -Mais alors, si tu as besoin d'autant de contextes dans ton application, comment faire ? -Et bien, il existe des solutions pour éviter le **context hell** : - -- Utiliser des bibliothèques tierces comme Redux _(solution lourde, mais très puissante)_ -- Créer un nouveau composant qui va regrouper tous les contextes _(solution plus légère, mais plus difficile à maintenir)_ - -N'étant pas un grand fan de Redux, je vais plutôt te présenter la deuxième solution. -Mais si tu veux en savoir plus sur Redux, n'hésite pas à consulter la documentation officielle ! - -### Résoudre le context hell avec un composant dédié - -Parlons de ce fameux composant qui va regrouper tous les contextes ! -On ne parle pas ici d'un simple composant Providers qui va imbriquer tous les Provider de nos contextes, mais d'une solution plus élégante. - -Après tout, nous sommes des feignants développeurs, non ? 😏 - -Réfléchissons à ce que l'on veut faire : - -- On veut pouvoir regrouper tous les contextes dans un seul composant. -- On veut pouvoir ajouter ou supprimer des contextes facilement. -- On veut pouvoir facilement les ordonner entre eux. -- On veut éviter le **context hell**. - -Et si on créait un composant Providers qui va nous permettre de faire tout ça ? - -{% tabs defaultSelectedTab="jsx" %} - -{% tab value="jsx" label="JSX" %} - -```jsx -const Providers = ({ providers, children }) => { - return ( - <> - {/** Ouverture des providers */} - {children} - {/** Fermeture des providers */} - - ); -}; -``` - -{% /tab %} - -{% tab value="tsx" label="TSX" %} - -```tsx -import type { ReactNode } from "react"; - -type ProvidersProps = { - providers: ReactNode[]; - children: ReactNode; -}; - -const Providers = ({ providers, children }: ProvidersProps) => { - return ( - <> - {/** Ouverture des providers */} - {children} - {/** Fermeture des providers */} - - ); -}; -``` - -{% /tab %} - -{% /tabs %} - -Ici on ne va pas remettre une cascade de Provider comme on a pu le voir plus tôt. -On va chercher à créer une fonction qui va nous permettre de les imbriquer les uns dans les autres. - -{% tabs defaultSelectedTab="jsx" %} - -{% tab value="jsx" label="JSX" %} - -```jsx -const nest = (children, component) => { - return React.cloneElement(component, {}, children); -}; -``` - -{% /tab %} - -{% tab value="tsx" label="TSX" %} - -```tsx -const nest = (children: ReactNode, component: ReactNode) => { - return React.cloneElement(component, {}, children); -}; -``` - -{% /tab %} - -{% /tabs %} - -{% callout type="note" title="React.cloneElement" %} - -`React.cloneElement` est une fonction qui va permettre de cloner un élément React en lui passant de nouvelles propriétés. -Cela va nous permettre de créer une nouvelle arborescence de composants sans modifier l'arborescence actuelle. - -Le premier argument est l'élément à cloner _(le composant)_, et le deuxième argument est un objet contenant les nouvelles propriétés. -Le troisième argument est le contenu de l'élément cloné _(les enfants)_. - -{% /callout %} - -Et maintenant, on va pouvoir utiliser notre fonction `nest` pour imbriquer nos Provider en utilisant la méthode `reduceRight` : - -{% tabs defaultSelectedTab="jsx" %} - -{% tab value="jsx" label="JSX" %} - -```jsx -const nest = (children, component) => { - return React.cloneElement(component, {}, children); -}; - -const Providers = ({ providers, children }) => { - return providers.reduceRight(nest, children); -}; -``` - -{% /tab %} - -{% tab value="tsx" label="TSX" %} - -```tsx -import type { ReactNode } from "react"; - -type ProvidersProps = { - providers: ReactNode[]; - children: ReactNode; -}; - -const nest = (children: ReactNode, component: ReactNode) => { - return React.cloneElement(component, {}, children); -}; - -const Providers = ({ providers, children }: ProvidersProps) => { - return providers.reduceRight(nest, children); -}; -``` - -{% /tab %} - -{% /tabs %} - -{% callout type="note" title="reduceRight" %} - -reduceRight est une méthode qui va permettre de réduire un tableau _(ou un objet)_ en appliquant une fonction de rappel de droite à gauche. -Cela va nous permettre de réduire un tableau de `Provider` en les imbriquant les uns dans les autres sans se soucier de l'ordre _(qui est défini par le tableau)_. - -Dans l'idée, on commence par le **dernier** élément du tableau, et on l'imbrique avec l'élément **précédent** du tableau et ainsi de suite jusqu'au **premier** élément du tableau. -Chaque itération va créer un nouvel élément imbriqué dans le précédent, en appelant la fonction `nest` qui est passée en argument. - -{% /callout %} - -Et voilà ! Il ne nous reste plus qu'à utiliser notre composant `Providers` pour regrouper tous nos `Provider` : - -```jsx -root.render( - - , - , - , - , - , - , - , - // ... - ]} - > - - - , -); -``` - -Évidemment le fichier contiendra toujours beaucoup de lignes, mais au moins, on a évité le **context hell** ! -Il sera nettement plus facile de modifier l'ordre des Provider ou d'en ajouter de nouveaux. - -## Conclusion - -Ça casse un peu la tête, mais les contextes sont un outil très puissant pour diffuser des données dans nos applications React. - -C'est aussi une excellente solution pour éviter d'utiliser des bibliothèques tierces comme Redux _(qui est très bien, mais qui peut être un peu lourd pour des petites applications)_. -On prendra d'ailleurs le temps de parler de Redux et de Zustand dans un prochain article 😉 - -Et si tu as besoin de plusieurs contextes dans ton application, n'oublie pas de réfléchir à l'utilisation de notre composant Providers pour éviter le **context hell**. diff --git a/app/pages/docs/react/use-context/tabs.tsx b/app/pages/docs/react/use-context/tabs.tsx new file mode 100644 index 0000000..a8e091c --- /dev/null +++ b/app/pages/docs/react/use-context/tabs.tsx @@ -0,0 +1,397 @@ +import { Snippet } from "@/components/Snippet"; +import { name } from "eslint-plugin-prettier/recommended"; + +const reactNestedPropsSnippets = [ + { + name: "JSX", + codeLanguage: "jsx", + withLineNumbers: true, + code: `import { useState } from "react"; + +const App = () => { + const [theme, setTheme] = useState("light"); + + return ; +}; + +const A = ({ theme, setTheme }) => { + return ; +}; + +const B = ({ theme, setTheme }) => { + return ; +};`, + }, + { + name: "TSX", + codeLanguage: "tsx", + withLineNumbers: true, + code: `import type { Dispatch, SetStateAction } from "react"; + +import { useState } from "react"; + +type Theme = "light" | "dark"; + +const App = () => { + const [theme, setTheme] = useState("light"); + + return ; +}; + +const A = ({ theme, setTheme }: { theme: Theme; setTheme: Dispatch> }) => { + return ; +}; + +const B = ({ theme, setTheme }: { theme: Theme; setTheme: Dispatch> }) => { + return ; +};`, + }, +]; + +const reactCreateContextSnippets = [ + { + name: "JSX", + codeLanguage: "jsx", + withLineNumbers: true, + code: `import { createContext } from "react"; + +// On crée notre contexte, avec une valeur par défaut : un thème clair +const ThemeContext = createContext({ + theme: "light", + setTheme: () => {}, +});`, + }, + { + name: "TSX", + codeLanguage: "tsx", + withLineNumbers: true, + code: `import type { Dispatch, SetStateAction } from "react"; + +import { createContext } from "react"; + +// On crée un type pour les valeurs de thème +export type Theme = "light" | "dark"; + +// On crée un type pour notre contexte +type ThemeContextType = { + theme: Theme; + setTheme: Dispatch>; +}; + +// On crée notre contexte, avec une valeur par défaut : un thème clair +const ThemeContext = createContext({ + theme: "light", + setTheme: () => {}, +});`, + }, +]; + +const reactContextProviderSnippets = [ + { + name: "JSX", + codeLanguage: "jsx", + withLineNumbers: true, + code: `import { useState } from "react"; + +const App = () => { + const [theme, setTheme] = useState("light"); + + return ( + + + + ); +};`, + }, + { + name: "TSX", + codeLanguage: "tsx", + withLineNumbers: true, + code: `import type { Theme } from "./ThemeContext"; + +import { useState } from "react"; + +const App = () => { + const [theme, setTheme] = useState("light"); + + return ( + + + + ); +};`, + }, +]; + +const reactContextProviderWithValuesSnippets = [ + { + name: "JSX", + codeLanguage: "jsx", + withLineNumbers: true, + code: `import { createContext, useState } from "react"; + +const ThemeContext = createContext({ + theme: "light", + setTheme: () => {}, +}); + +const ThemeProvider = ({ children }) => { + const [theme, setTheme] = useState("light"); + + return {children}; +}; + +export { ThemeContext, ThemeProvider };`, + }, + { + name: "TSX", + codeLanguage: "tsx", + withLineNumbers: true, + code: `import type { ReactNode } from "react"; + +import { createContext, useState } from "react"; + +export type Theme = "light" | "dark"; + +type ThemeContextType = { + theme: Theme; + setTheme: Dispatch>; +}; + +const ThemeContext = createContext({ + theme: "light", + setTheme: () => {}, +}); + +type ThemeProviderProps = { + children: ReactNode; +}; + +const ThemeProvider = ({ children }: ThemeProviderProps) => { + const [theme, setTheme] = useState("light"); + + return {children}; +}; + +export { ThemeContext, ThemeProvider };`, + }, +]; + +const reactContextProviderInAppSnippets = [ + { + name: "App.jsx", + codeLanguage: "jsx", + withLineNumbers: true, + code: `import { ThemeProvider } from "./ThemeContext"; +import A from "./A"; + +const App = () => { + return ( + + + + ); +};`, + }, +]; + +const reactUseContextSnippets = [ + { + name: "Utilisation du hook `useContext`", + codeLanguage: "jsx", + withLineNumbers: true, + code: `import { ThemeContext } from "./ThemeContext"; +import { useContext } from "react"; + +const C = () => { + const { theme, setTheme } = useContext(ThemeContext); + + return <>{/** JSX */}; +};`, + }, +]; + +const reactContextHellSnippets = [ + { + name: "Exemple de contexte imbriqué", + codeLanguage: "jsx", + withLineNumbers: true, + code: `root.render( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + , +);`, + }, +]; + +const reactContextProvidersComponentSnippets = [ + { + name: "JSX", + codeLanguage: "jsx", + withLineNumbers: true, + code: `const Providers = ({ providers, children }) => { + return ( + <> + {/** Ouverture des providers */} + {children} + {/** Fermeture des providers */} + + ); +};`, + }, + { + name: "TSX", + codeLanguage: "tsx", + withLineNumbers: true, + code: `import type { ReactNode } from "react"; + +type ProvidersProps = { + providers: ReactNode[]; + children: ReactNode; +}; + +const Providers = ({ providers, children }: ProvidersProps) => { + return ( + <> + {/** Ouverture des providers */} + {children} + {/** Fermeture des providers */} + + ); +};`, + }, +]; + +const reactNestFunctionSnippets = [ + { + name: "JSX", + codeLanguage: "jsx", + code: `const nest = (children, component) => { + return React.cloneElement(component, {}, children); +};`, + }, + { + name: "TSX", + codeLanguage: "tsx", + code: `const nest = (children: ReactNode, component: ReactNode) => { + return React.cloneElement(component, {}, children); +};`, + }, +]; + +const reactNestFunctionWithReduceRightSnippets = [ + { + name: "JSX", + codeLanguage: "jsx", + code: `const nest = (children, component) => { + return React.cloneElement(component, {}, children); +}; + +const Providers = ({ providers, children }) => { + return providers.reduceRight(nest, children); +};`, + }, + { + name: "TSX", + codeLanguage: "tsx", + code: `import type { ReactNode } from "react"; + +type ProvidersProps = { + providers: ReactNode[]; + children: ReactNode; +}; + +const nest = (children: ReactNode, component: ReactNode) => { + return React.cloneElement(component, {}, children); +}; + +const Providers = ({ providers, children }: ProvidersProps) => { + return providers.reduceRight(nest, children); +};`, + }, +]; + +const reactCleanerProvidersSnippets = [ + { + name: "Import lisible et maintenable pour les providers", + codeLanguage: "jsx", + code: `root.render( + + , + , + , + , + , + , + , + // ... + ]} + > + + + , +);`, + }, +]; + +export default { + reactNestedProps: () => , + reactCreateContext: () => , + reactContextProvider: () => ( + + ), + reactContextProviderWithValues: () => ( + + ), + reactContextProviderInApp: () => ( + + ), + reactUseContext: () => , + reactContextHell: () => , + reactContextProvidersComponent: () => ( + + ), + reactNestFunction: () => , + reactNestFunctionWithReduceRight: () => ( + + ), + reactCleanerProviders: () => ( + + ), +};