rework/lightweight #12
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
export type CounterAction =
|
export type CounterAction =
|
||||||
| { type: CounterActionTypes.INCREMENT }
|
| { type: CounterActionTypes.INCREMENT }
|
||||||
| { type: CounterActionTypes.DECREMENT }
|
| { type: CounterActionTypes.DECREMENT }
|
||||||
|
|||||||
@ -61,7 +61,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.token.property,
|
.token.property,
|
||||||
.token.tag {
|
.token.tag,
|
||||||
|
.token.constant {
|
||||||
color: #E55649;
|
color: #E55649;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { Snippet } from "@/components/Snippet";
|
import { Snippet } from "@/components/Snippet";
|
||||||
import { name } from "eslint-plugin-prettier/recommended";
|
|
||||||
|
|
||||||
const reactNestedPropsSnippets = [
|
const reactNestedPropsSnippets = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,15 +4,16 @@ description: Découvre les hooks de React, une fonctionnalité qui te permet de
|
|||||||
tags: [Frontend, React, JavaScript, TypeScript, Bibliothèque, Interface utilisateur (UI)]
|
tags: [Frontend, React, JavaScript, TypeScript, Bibliothèque, Interface utilisateur (UI)]
|
||||||
---
|
---
|
||||||
|
|
||||||
|
import Callout from "@/components/Callout";
|
||||||
|
import tabs from "./tabs";
|
||||||
|
|
||||||
Si tu as lu les précédentes pages concernant les hooks de React _(useState, useEffect et useContext)_, tu as déjà une bonne vision de la manière dont tu peux concevoir une application React.
|
Si tu as lu les précédentes pages concernant les hooks de React _(useState, useEffect et useContext)_, tu as déjà une bonne vision de la manière dont tu peux concevoir une application React.
|
||||||
|
|
||||||
Mais si je te dis que tu peux aller encore plus loin avec useReducer pour la gestion des états, est-ce que tu serais intéressé·e ? 🤔
|
Mais si je te dis que tu peux aller encore plus loin avec useReducer pour la gestion des états, est-ce que tu serais intéressé·e ? 🤔
|
||||||
|
|
||||||
{% callout type="question" title="Pourquoi ? useState ne suffit pas ?" %}
|
<Callout type="question" title="Pourquoi ? useState ne suffit pas ?">
|
||||||
|
|
||||||
Le hook `useState` est génial et essentiel pour gérer l'état local d'un composant, mais il n'est pas adapté pour des états dits "complexes" ou pour des états qui dépendent les uns des autres.
|
Le hook `useState` est génial et essentiel pour gérer l'état local d'un composant, mais il n'est pas adapté pour des états dits "complexes" ou pour des états qui dépendent les uns des autres.
|
||||||
|
</Callout>
|
||||||
{% /callout %}
|
|
||||||
|
|
||||||
## Qu'est-ce que le hook useReducer ?
|
## Qu'est-ce que le hook useReducer ?
|
||||||
|
|
||||||
@ -46,17 +47,7 @@ Comme expliqué plus tôt, un reducer est une fonction qui prend en paramètre u
|
|||||||
|
|
||||||
Parlons dans un premier temps de la signature d'un reducer :
|
Parlons dans un premier temps de la signature d'un reducer :
|
||||||
|
|
||||||
{% tabs defaultSelectedTab="jsx" %}
|
<tabs.reactReducerExample />
|
||||||
|
|
||||||
{% tab value="jsx" label="JSX" %}
|
|
||||||
{% snippet path="react/reducer/reducer-example.jsx" language="jsx" showLineNumbers=true /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% tab value="tsx" label="TSX" %}
|
|
||||||
{% snippet path="react/reducer/reducer-example.tsx" language="tsx" showLineNumbers=true /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% /tabs %}
|
|
||||||
|
|
||||||
Comme tu peux le voir, on récupère bien deux paramètres : `state` et `action`.
|
Comme tu peux le voir, on récupère bien deux paramètres : `state` et `action`.
|
||||||
|
|
||||||
@ -70,19 +61,17 @@ L'état est contraint au principe d'**immutabilité**.
|
|||||||
|
|
||||||
On fera donc des `return` de l'état actuel avec les modifications nécessaires.
|
On fera donc des `return` de l'état actuel avec les modifications nécessaires.
|
||||||
|
|
||||||
{% callout type="note" title="Pourquoi déverser le contenu de l'état actuel ?" %}
|
<Callout type="note" title="Pourquoi déverser le contenu de l'état actuel ?">
|
||||||
|
|
||||||
Si on ne déverse pas le contenu de l'état actuel, on perdrait les propriétés qui ne sont pas modifiées par l'action.
|
Si on ne déverse pas le contenu de l'état actuel, on perdrait les propriétés qui ne sont pas modifiées par l'action.
|
||||||
|
|
||||||
En déversant le contenu de l'état actuel, on s'assure de ne pas perdre ces propriétés.
|
En déversant le contenu de l'état actuel, on s'assure de ne pas perdre ces propriétés.
|
||||||
|
|
||||||
Par exemple :
|
Par exemple :
|
||||||
|
|
||||||
{% snippet path="react/reducer/reducer-why-spread-operator.jsx" language="jsx" showLineNumbers=true /%}
|
<tabs.reactReducerWhySpreadOperator />
|
||||||
|
|
||||||
On perdrait ici la propriété `message` si on ne la déversait pas dans le nouvel état.
|
On perdrait ici la propriété `message` si on ne la déversait pas dans le nouvel état.
|
||||||
|
</Callout>
|
||||||
{% /callout %}
|
|
||||||
|
|
||||||
## Comment utiliser useReducer ?
|
## Comment utiliser useReducer ?
|
||||||
|
|
||||||
@ -90,68 +79,34 @@ Maintenant que tu as une idée de ce qu'est un reducer, voyons comment l'utilise
|
|||||||
|
|
||||||
Naturellement, on va commencer par importer le hook `useReducer` :
|
Naturellement, on va commencer par importer le hook `useReducer` :
|
||||||
|
|
||||||
```js
|
<tabs.reactUseReducerImport />
|
||||||
import { useReducer } from "react";
|
|
||||||
```
|
|
||||||
|
|
||||||
Ensuite, on va définir notre état initial :
|
Ensuite, on va définir notre état initial :
|
||||||
|
|
||||||
{% tabs defaultSelectedTab="js" %}
|
<tabs.reactReducerInitialState />
|
||||||
|
|
||||||
{% tab value="js" label="JavaScript" %}
|
|
||||||
{% snippet path="react/reducer/reducer-initial-state.js" language="js" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% tab value="ts" label="TypeScript" %}
|
|
||||||
{% snippet path="react/reducer/reducer-initial-state.ts" language="ts" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% /tabs %}
|
|
||||||
|
|
||||||
On peut maintenant définir notre reducer :
|
On peut maintenant définir notre reducer :
|
||||||
|
|
||||||
{% tabs defaultSelectedTab="js" %}
|
<tabs.reactCounterReducer />
|
||||||
|
|
||||||
{% tab value="js" label="JavaScript" %}
|
|
||||||
{% snippet path="react/reducer/reducer.js" language="js" showLineNumbers=true /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% tab value="ts" label="TypeScript" %}
|
|
||||||
{% snippet path="react/reducer/reducer.ts" language="ts" showLineNumbers=true /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% /tabs %}
|
|
||||||
|
|
||||||
{% callout type="question" title="C'est quoi `action.payload` ?" %}
|
|
||||||
|
|
||||||
|
<Callout type="question" title="C'est quoi `action.payload` ?">
|
||||||
La propriété `payload` de l'action est optionnelle. Il s'agit d'une convention pour passer des données à l'action.
|
La propriété `payload` de l'action est optionnelle. Il s'agit d'une convention pour passer des données à l'action.
|
||||||
|
|
||||||
Le `!` après `action.payload` signifie que l'on est sûr que `payload` est défini.
|
Le `!` après `action.payload` signifie que l'on est sûr que `payload` est défini.
|
||||||
Cela permet d'éviter une erreur de type avec TypeScript.
|
Cela permet d'éviter une erreur de type avec TypeScript.
|
||||||
|
|
||||||
Dans le cas du type `SET`, le payload sera défini obligatoirement avec un nombre qui sera la nouvelle valeur de la propriété `count` de l'état.
|
Dans le cas du type `SET`, le payload sera défini obligatoirement avec un nombre qui sera la nouvelle valeur de la propriété `count` de l'état.
|
||||||
|
</Callout>
|
||||||
{% /callout %}
|
|
||||||
|
|
||||||
Enfin, on peut utiliser le hook useReducer dans notre composant :
|
Enfin, on peut utiliser le hook useReducer dans notre composant :
|
||||||
|
|
||||||
{% tabs defaultSelectedTab="js" %}
|
<tabs.reactUseReducerUsage />
|
||||||
|
|
||||||
{% tab value="js" label="JavaScript" %}
|
|
||||||
{% snippet path="react/reducer/reducer-hook.js" language="js" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% tab value="ts" label="TypeScript" %}
|
|
||||||
{% snippet path="react/reducer/reducer-hook.ts" language="ts" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% /tabs %}
|
|
||||||
|
|
||||||
`state` contient l'état actuel, et `dispatch` est une fonction qui permet d'envoyer une action au reducer.
|
`state` contient l'état actuel, et `dispatch` est une fonction qui permet d'envoyer une action au reducer.
|
||||||
|
|
||||||
Pour modifier l'état, on va donc appeler `dispatch` avec une action :
|
Pour modifier l'état, on va donc appeler `dispatch` avec une action :
|
||||||
|
|
||||||
{% snippet path="react/reducer/reducer-dispatch-increment.js" language="js" /%}
|
<tabs.reactDispatchIncrement />
|
||||||
|
|
||||||
Et voilà, tu sais maintenant comment utiliser `useReducer` dans une application React ! 🎉
|
Et voilà, tu sais maintenant comment utiliser `useReducer` dans une application React ! 🎉
|
||||||
|
|
||||||
@ -175,27 +130,15 @@ Pour contrer ces problèmes, on va créer des actions et des types d'actions pou
|
|||||||
|
|
||||||
Nos types d'actions seront tous des chaînes de caractères. On va donc pouvoir les définir sous forme de constantes.
|
Nos types d'actions seront tous des chaînes de caractères. On va donc pouvoir les définir sous forme de constantes.
|
||||||
|
|
||||||
{% snippet path="react/reducer/reducer-actions-constants.js" language="js" /%}
|
<tabs.reactActionsConstants />
|
||||||
|
|
||||||
{% callout type="note" title="Regrouper les exports" %}
|
|
||||||
|
|
||||||
|
<Callout type="note" title="Regrouper les exports">
|
||||||
Et là, tu te dis : "Pourquoi ne pas regrouper les exports dans un seul objet ?"
|
Et là, tu te dis : "Pourquoi ne pas regrouper les exports dans un seul objet ?"
|
||||||
|
|
||||||
Bien vu ! Et pour TypeScript, on peut aller encore plus loin en créant un `enum` pour les types d'actions 😉
|
Bien vu ! Et pour TypeScript, on peut aller encore plus loin en créant un `enum` pour les types d'actions 😉
|
||||||
|
|
||||||
{% tabs defaultSelectedTab="js" %}
|
<tabs.reactActionsEnum />
|
||||||
|
</Callout>
|
||||||
{% tab value="js" label="JavaScript" %}
|
|
||||||
{% snippet path="react/reducer/reducer-actions-enum.js" language="js" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% tab value="ts" label="TypeScript" %}
|
|
||||||
{% snippet path="react/reducer/reducer-actions-enum.ts" language="ts" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% /tabs %}
|
|
||||||
|
|
||||||
{% /callout %}
|
|
||||||
|
|
||||||
### Typage des actions
|
### Typage des actions
|
||||||
|
|
||||||
@ -203,31 +146,21 @@ Si tu utilises JavaScript, je suis désolé de te dire que tu ne peux pas **fort
|
|||||||
|
|
||||||
En revanche, si tu utilises TypeScript, tu peux définir les actions de la manière suivante :
|
En revanche, si tu utilises TypeScript, tu peux définir les actions de la manière suivante :
|
||||||
|
|
||||||
{% snippet path="react/reducer/reducer-actions-union.ts" language="ts" /%}
|
<tabs.reactActionsUnion />
|
||||||
|
|
||||||
Tu pourras alors utiliser `CounterAction` pour typer les actions de ton reducer :
|
Tu pourras alors utiliser `CounterAction` pour typer les actions de ton reducer :
|
||||||
|
|
||||||
{% snippet path="react/reducer/reducer-actions-union-use.ts" language="ts" /%}
|
<tabs.reactActionsUnionUsage />
|
||||||
|
|
||||||
### Action creators
|
### Action creators
|
||||||
|
|
||||||
Pour éviter de se tromper dans le type de l'action, on peut se créer des fonctions qui vont nous permettre de créer des actions.
|
Pour éviter de se tromper dans le type de l'action, on peut se créer des fonctions qui vont nous permettre de créer des actions.
|
||||||
|
|
||||||
{% tabs defaultSelectedTab="js" %}
|
<tabs.reactActionCreator />
|
||||||
|
|
||||||
{% tab value="js" label="JavaScript" %}
|
|
||||||
{% snippet path="react/reducer/reducer-action-creator.js" language="js" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% tab value="ts" label="TypeScript" %}
|
|
||||||
{% snippet path="react/reducer/reducer-action-creator.ts" language="ts" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% /tabs %}
|
|
||||||
|
|
||||||
Maintenant le dispatch de nos actions sera beaucoup plus simple et éviter davantage les erreurs lors du développement !
|
Maintenant le dispatch de nos actions sera beaucoup plus simple et éviter davantage les erreurs lors du développement !
|
||||||
|
|
||||||
{% snippet path="react/reducer/reducer-dispatch-action-creator.js" language="js" /%}
|
<tabs.reactDispatchActionCreator />
|
||||||
|
|
||||||
## Les fichiers complets
|
## Les fichiers complets
|
||||||
|
|
||||||
@ -236,64 +169,36 @@ Pour t'aider à mieux comprendre le fonctionnement du hook `useReducer` et comme
|
|||||||
|
|
||||||
### Fichier counterReducer.js ou counterReducer.ts
|
### Fichier counterReducer.js ou counterReducer.ts
|
||||||
|
|
||||||
{% tabs defaultSelectedTab="js" %}
|
<tabs.reactFileCounterReducer />
|
||||||
|
|
||||||
{% tab value="js" label="JavaScript" %}
|
|
||||||
{% snippet path="react/reducer/file-counterReducer.js" language="js" showLineNumbers=true label="src/reducers/counterReducer.js" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% tab value="ts" label="TypeScript" %}
|
|
||||||
{% snippet path="react/reducer/file-counterReducer.ts" language="ts" showLineNumbers=true label="src/reducers/counterReducer.ts" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% /tabs %}
|
|
||||||
|
|
||||||
### Fichier Counter.jsx ou Counter.tsx
|
### Fichier Counter.jsx ou Counter.tsx
|
||||||
|
|
||||||
{% tabs defaultSelectedTab="jsx" %}
|
<tabs.reactFileCounterComponent />
|
||||||
|
|
||||||
{% tab value="jsx" label="JSX" %}
|
|
||||||
{% snippet path="react/reducer/file-counter.jsx" language="jsx" showLineNumbers=true label="src/components/Counter.jsx" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% tab value="tsx" label="TSX" %}
|
|
||||||
{% snippet path="react/reducer/file-counter.tsx" language="tsx" showLineNumbers=true label="src/components/Counter.tsx" /%}
|
|
||||||
{% /tab %}
|
|
||||||
|
|
||||||
{% /tabs %}
|
|
||||||
|
|
||||||
## C'est l'heure des questions !
|
## C'est l'heure des questions !
|
||||||
|
|
||||||
{% callout type="question" title="Quand utiliser `useReducer` ?" %}
|
<Callout type="question" title="Quand utiliser `useReducer` ?">
|
||||||
|
|
||||||
- **A** - Pour des états simples
|
- **A** - Pour des états simples
|
||||||
- **B** - Pour des états complexes ou des états qui dépendent les uns des autres
|
- **B** - Pour des états complexes ou des états qui dépendent les uns des autres
|
||||||
|
</Callout>
|
||||||
|
|
||||||
{% /callout %}
|
<Callout type="question" title="Quelle est la signature d'un reducer ?">
|
||||||
|
|
||||||
{% callout type="question" title="Quelle est la signature d'un reducer ?" %}
|
|
||||||
|
|
||||||
- **A** - `(state, action) => { /* ... */ }`
|
- **A** - `(state, action) => { /* ... */ }`
|
||||||
- **B** - `(action, state) => { /* ... */ }`
|
- **B** - `(action, state) => { /* ... */ }`
|
||||||
- **C** - `(state) => { /* ... */ }`
|
- **C** - `(state) => { /* ... */ }`
|
||||||
- **D** - `(action) => { /* ... */ }`
|
- **D** - `(action) => { /* ... */ }`
|
||||||
|
</Callout>
|
||||||
|
|
||||||
{% /callout %}
|
<Callout type="question" title="Pourquoi déverser le contenu de l'état actuel dans le nouvel état ?">
|
||||||
|
|
||||||
{% callout type="question" title="Pourquoi déverser le contenu de l'état actuel dans le nouvel état ?" %}
|
|
||||||
|
|
||||||
- **A** - Pour rendre le code plus lisible
|
- **A** - Pour rendre le code plus lisible
|
||||||
- **B** - Pour ne pas perdre les propriétés qui ne sont pas modifiées par l'action
|
- **B** - Pour ne pas perdre les propriétés qui ne sont pas modifiées par l'action
|
||||||
|
</Callout>
|
||||||
|
|
||||||
{% /callout %}
|
<Callout type="question" title="Pourquoi utiliser des constantes pour les types d'actions ?">
|
||||||
|
|
||||||
{% callout type="question" title="Pourquoi utiliser des constantes pour les types d'actions ?" %}
|
|
||||||
|
|
||||||
- **A** - Pour rendre le code plus lisible
|
- **A** - Pour rendre le code plus lisible
|
||||||
- **B** - Pour alourdir inutillement le code
|
- **B** - Pour alourdir inutillement le code
|
||||||
- **C** - Pour éviter de se tromper dans le type de l'action
|
- **C** - Pour éviter de se tromper dans le type de l'action
|
||||||
|
</Callout>
|
||||||
{% /callout %}
|
|
||||||
|
|
||||||
## Conclusion
|
## Conclusion
|
||||||
|
|
||||||
420
app/pages/docs/react/use-reducer/tabs.tsx
Normal file
420
app/pages/docs/react/use-reducer/tabs.tsx
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
import { Snippet } from "@/components/Snippet";
|
||||||
|
|
||||||
|
const reactReducerExampleSnippets = [
|
||||||
|
{
|
||||||
|
name: "JSX",
|
||||||
|
codeLanguage: "jsx",
|
||||||
|
withLineNumbers: true,
|
||||||
|
code: `const reducer = (state, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case "TYPE_1":
|
||||||
|
return { ...state /* Nouvel état */ };
|
||||||
|
case "TYPE_2":
|
||||||
|
return { ...state /* Nouvel état */ };
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TSX",
|
||||||
|
codeLanguage: "tsx",
|
||||||
|
withLineNumbers: true,
|
||||||
|
code: `const reducer = (state: State, action: Action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case "TYPE_1":
|
||||||
|
return { ...state /* Nouvel état */ };
|
||||||
|
case "TYPE_2":
|
||||||
|
return { ...state /* Nouvel état */ };
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactReducerWhySpreadOperatorSnippets = [
|
||||||
|
{
|
||||||
|
name: "Retour sans déversement de l'état",
|
||||||
|
codeLanguage: "jsx",
|
||||||
|
withLineNumbers: true,
|
||||||
|
code: `const initialState = { count: 0, message: "Hello" };
|
||||||
|
|
||||||
|
const reducer = (state, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case "INCREMENT":
|
||||||
|
return { count: state.count + 1 };
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactUseReducerImportSnippets = [
|
||||||
|
{
|
||||||
|
name: "Importation de useReducer",
|
||||||
|
codeLanguage: "jsx",
|
||||||
|
code: `import { useReducer } from "react";`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactReducerInitialStateSnippets = [
|
||||||
|
{
|
||||||
|
name: "JSX",
|
||||||
|
codeLanguage: "jsx",
|
||||||
|
code: "const initialState = { count: 0 };",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TSX",
|
||||||
|
codeLanguage: "tsx",
|
||||||
|
code: `type State = {
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
const initialState: State = { count: 0 };`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactCounterReducerSnippets = [
|
||||||
|
{
|
||||||
|
name: "JSX",
|
||||||
|
codeLanguage: "jsx",
|
||||||
|
withLineNumbers: true,
|
||||||
|
code: `const reducer = (state, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case "INCREMENT":
|
||||||
|
return { ...state, count: state.count + 1 };
|
||||||
|
case "DECREMENT":
|
||||||
|
return { ...state, count: state.count - 1 };
|
||||||
|
case "RESET":
|
||||||
|
return { ...state, count: 0 };
|
||||||
|
case "SET":
|
||||||
|
return { ...state, count: action.payload };
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TSX",
|
||||||
|
codeLanguage: "tsx",
|
||||||
|
withLineNumbers: true,
|
||||||
|
code: `type State = {
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Action = {
|
||||||
|
type: "INCREMENT" | "DECREMENT" | "RESET" | "SET";
|
||||||
|
payload?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const reducer = (state: State, action: Action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case "INCREMENT":
|
||||||
|
return { ...state, count: state.count + 1 };
|
||||||
|
case "DECREMENT":
|
||||||
|
return { ...state, count: state.count - 1 };
|
||||||
|
case "RESET":
|
||||||
|
return { ...state, count: 0 };
|
||||||
|
case "SET":
|
||||||
|
return { ...state, count: action.payload! };
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactUseReducerUsageSnippets = [
|
||||||
|
{
|
||||||
|
name: "JSX",
|
||||||
|
codeLanguage: "jsx",
|
||||||
|
code: "const [state, dispatch] = useReducer(reducer, initialState);",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TSX",
|
||||||
|
codeLanguage: "tsx",
|
||||||
|
code: "const [state, dispatch] = useReducer<State, Action>(reducer, initialState);",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactDispatchIncrementSnippets = [
|
||||||
|
{
|
||||||
|
name: "Exemple d'utilisation de dispatch",
|
||||||
|
codeLanguage: "jsx",
|
||||||
|
code: `dispatch({ type: "INCREMENT" });`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactActionsConstantsSnippets = [
|
||||||
|
{
|
||||||
|
name: "Création et exportation de constantes d'actions",
|
||||||
|
codeLanguage: "jsx",
|
||||||
|
code: `export const INCREMENT = "INCREMENT";
|
||||||
|
export const DECREMENT = "DECREMENT";
|
||||||
|
export const RESET = "RESET";
|
||||||
|
export const SET = "SET";`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactActionsEnumSnippets = [
|
||||||
|
{
|
||||||
|
name: "JavaScript",
|
||||||
|
codeLanguage: "javascript",
|
||||||
|
code: `export const CounterActionTypes = {
|
||||||
|
INCREMENT: "INCREMENT",
|
||||||
|
DECREMENT: "DECREMENT",
|
||||||
|
RESET: "RESET",
|
||||||
|
SET: "SET",
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TypeScript",
|
||||||
|
codeLanguage: "typescript",
|
||||||
|
code: `export const enum CounterActionTypes {
|
||||||
|
INCREMENT = "INCREMENT",
|
||||||
|
DECREMENT = "DECREMENT",
|
||||||
|
RESET = "RESET",
|
||||||
|
SET = "SET",
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactActionsUnionSnippets = [
|
||||||
|
{
|
||||||
|
name: "Union de types d'actions",
|
||||||
|
codeLanguage: "typescript",
|
||||||
|
code: `export type CounterAction =
|
||||||
|
| { type: CounterActionTypes.INCREMENT }
|
||||||
|
| { type: CounterActionTypes.DECREMENT }
|
||||||
|
| { type: CounterActionTypes.RESET }
|
||||||
|
| { type: CounterActionTypes.SET; payload: number };`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactActionsUnionUsageSnippets = [
|
||||||
|
{
|
||||||
|
name: "Utilisation de l'union de types d'actions",
|
||||||
|
codeLanguage: "typescript",
|
||||||
|
code: `const reducer = (state: State, action: CounterAction) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case CounterActionTypes.INCREMENT:
|
||||||
|
return { ...state, count: state.count + 1 };
|
||||||
|
case CounterActionTypes.DECREMENT:
|
||||||
|
return { ...state, count: state.count - 1 };
|
||||||
|
case CounterActionTypes.RESET:
|
||||||
|
return { ...state, count: 0 };
|
||||||
|
case CounterActionTypes.SET:
|
||||||
|
return { ...state, count: action.payload };
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactActionCreatorSnippets = [
|
||||||
|
{
|
||||||
|
name: "JavaScript",
|
||||||
|
codeLanguage: "javascript",
|
||||||
|
code: `export const actions = {
|
||||||
|
increment: () => ({ type: CounterActionTypes.INCREMENT }),
|
||||||
|
decrement: () => ({ type: CounterActionTypes.DECREMENT }),
|
||||||
|
reset: () => ({ type: CounterActionTypes.RESET }),
|
||||||
|
set: (value) => ({ type: CounterActionTypes.SET, payload: value }),
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TypeScript",
|
||||||
|
codeLanguage: "typescript",
|
||||||
|
code: `export const actions = {
|
||||||
|
increment: (): CounterAction => ({ type: CounterActionTypes.INCREMENT }),
|
||||||
|
decrement: (): CounterAction => ({ type: CounterActionTypes.DECREMENT }),
|
||||||
|
reset: (): CounterAction => ({ type: CounterActionTypes.RESET }),
|
||||||
|
set: (value: number): CounterAction => ({ type: CounterActionTypes.SET, payload: value }),
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactDispatchActionCreatorSnippets = [
|
||||||
|
{
|
||||||
|
name: "Utilisation de l'action créateur avec dispatch",
|
||||||
|
codeLanguage: "javascript",
|
||||||
|
code: `dispatch(actions.increment());
|
||||||
|
dispatch(actions.set(10));`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactFileCounterReducerSnippets = [
|
||||||
|
{
|
||||||
|
name: "app/reducers/counterReducer.js",
|
||||||
|
codeLanguage: "javascript",
|
||||||
|
code: `const CounterActionTypes = {
|
||||||
|
INCREMENT: "INCREMENT",
|
||||||
|
DECREMENT: "DECREMENT",
|
||||||
|
RESET: "RESET",
|
||||||
|
SET: "SET",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const initialState = { count: 0 };
|
||||||
|
|
||||||
|
export const reducer = (state, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case CounterActionTypes.INCREMENT:
|
||||||
|
return { ...state, count: state.count + 1 };
|
||||||
|
case CounterActionTypes.DECREMENT:
|
||||||
|
return { ...state, count: state.count - 1 };
|
||||||
|
case CounterActionTypes.RESET:
|
||||||
|
return { ...state, count: 0 };
|
||||||
|
case CounterActionTypes.SET:
|
||||||
|
return { ...state, count: action.payload };
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
increment: () => ({ type: CounterActionTypes.INCREMENT }),
|
||||||
|
decrement: () => ({ type: CounterActionTypes.DECREMENT }),
|
||||||
|
reset: () => ({ type: CounterActionTypes.RESET }),
|
||||||
|
set: (value) => ({ type: CounterActionTypes.SET, payload: value }),
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "app/reducers/counterReducer.ts",
|
||||||
|
codeLanguage: "typescript",
|
||||||
|
code: `const enum CounterActionTypes {
|
||||||
|
INCREMENT = "INCREMENT",
|
||||||
|
DECREMENT = "DECREMENT",
|
||||||
|
RESET = "RESET",
|
||||||
|
SET = "SET",
|
||||||
|
}
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Action =
|
||||||
|
| { type: CounterActionTypes.INCREMENT }
|
||||||
|
| { type: CounterActionTypes.DECREMENT }
|
||||||
|
| { type: CounterActionTypes.RESET }
|
||||||
|
| { type: CounterActionTypes.SET; payload: number };
|
||||||
|
|
||||||
|
export const initialState: State = { count: 0 };
|
||||||
|
|
||||||
|
export const reducer = (state: State, action: Action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case CounterActionTypes.INCREMENT:
|
||||||
|
return { ...state, count: state.count + 1 };
|
||||||
|
case CounterActionTypes.DECREMENT:
|
||||||
|
return { ...state, count: state.count - 1 };
|
||||||
|
case CounterActionTypes.RESET:
|
||||||
|
return { ...state, count: 0 };
|
||||||
|
case CounterActionTypes.SET:
|
||||||
|
return { ...state, count: action.payload };
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
increment: (): Action => ({ type: CounterActionTypes.INCREMENT }),
|
||||||
|
decrement: (): Action => ({ type: CounterActionTypes.DECREMENT }),
|
||||||
|
reset: (): Action => ({ type: CounterActionTypes.RESET }),
|
||||||
|
set: (value: number): Action => ({ type: CounterActionTypes.SET, payload: value }),
|
||||||
|
};`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const reactFileCounterComponentSnippets = [
|
||||||
|
{
|
||||||
|
name: "app/components/Counter.jsx",
|
||||||
|
codeLanguage: "jsx",
|
||||||
|
code: `import { initialState, actions, reducer } from "../reducers/counterReducer";
|
||||||
|
import { useReducer } from "react";
|
||||||
|
|
||||||
|
const Counter = () => {
|
||||||
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Count: {state.count}</p>
|
||||||
|
|
||||||
|
<button onClick={() => dispatch(actions.increment())}>Increment</button>
|
||||||
|
|
||||||
|
<button onClick={() => dispatch(actions.decrement())}>Decrement</button>
|
||||||
|
|
||||||
|
<button onClick={() => dispatch(actions.reset())}>Reset</button>
|
||||||
|
|
||||||
|
<button onClick={() => dispatch(actions.set(10))}>Set counter to 10</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Counter;`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "app/components/Counter.tsx",
|
||||||
|
codeLanguage: "tsx",
|
||||||
|
code: `import { initialState, actions, reducer } from "../reducers/counterReducer";
|
||||||
|
import { useReducer } from "react";
|
||||||
|
|
||||||
|
const Counter = () => {
|
||||||
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<p>Count: {state.count}</p>
|
||||||
|
|
||||||
|
<button onClick={() => dispatch(actions.increment())}>Increment</button>
|
||||||
|
|
||||||
|
<button onClick={() => dispatch(actions.decrement())}>Decrement</button>
|
||||||
|
|
||||||
|
<button onClick={() => dispatch(actions.reset())}>Reset</button>
|
||||||
|
|
||||||
|
<button onClick={() => dispatch(actions.set(10))}>Set counter to 10</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Counter;`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
reactReducerExample: () => <Snippet snippets={reactReducerExampleSnippets} />,
|
||||||
|
reactReducerWhySpreadOperator: () => (
|
||||||
|
<Snippet snippets={reactReducerWhySpreadOperatorSnippets} />
|
||||||
|
),
|
||||||
|
reactUseReducerImport: () => (
|
||||||
|
<Snippet snippets={reactUseReducerImportSnippets} />
|
||||||
|
),
|
||||||
|
reactReducerInitialState: () => (
|
||||||
|
<Snippet snippets={reactReducerInitialStateSnippets} />
|
||||||
|
),
|
||||||
|
reactCounterReducer: () => <Snippet snippets={reactCounterReducerSnippets} />,
|
||||||
|
reactUseReducerUsage: () => (
|
||||||
|
<Snippet snippets={reactUseReducerUsageSnippets} />
|
||||||
|
),
|
||||||
|
reactDispatchIncrement: () => (
|
||||||
|
<Snippet snippets={reactDispatchIncrementSnippets} />
|
||||||
|
),
|
||||||
|
reactActionsConstants: () => (
|
||||||
|
<Snippet snippets={reactActionsConstantsSnippets} />
|
||||||
|
),
|
||||||
|
reactActionsEnum: () => <Snippet snippets={reactActionsEnumSnippets} />,
|
||||||
|
reactActionsUnion: () => <Snippet snippets={reactActionsUnionSnippets} />,
|
||||||
|
reactActionsUnionUsage: () => (
|
||||||
|
<Snippet snippets={reactActionsUnionUsageSnippets} />
|
||||||
|
),
|
||||||
|
reactActionCreator: () => <Snippet snippets={reactActionCreatorSnippets} />,
|
||||||
|
reactDispatchActionCreator: () => (
|
||||||
|
<Snippet snippets={reactDispatchActionCreatorSnippets} />
|
||||||
|
),
|
||||||
|
reactFileCounterReducer: () => (
|
||||||
|
<Snippet snippets={reactFileCounterReducerSnippets} />
|
||||||
|
),
|
||||||
|
reactFileCounterComponent: () => (
|
||||||
|
<Snippet snippets={reactFileCounterComponentSnippets} />
|
||||||
|
),
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user