feat: Add React reducer tabs and snippets for documentation
This commit is contained in:
parent
8ad370940f
commit
5b9b5583b2
@ -1,4 +1,3 @@
|
||||
|
||||
export type CounterAction =
|
||||
| { type: CounterActionTypes.INCREMENT }
|
||||
| { type: CounterActionTypes.DECREMENT }
|
||||
|
||||
@ -61,7 +61,8 @@
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag {
|
||||
.token.tag,
|
||||
.token.constant {
|
||||
color: #E55649;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { Snippet } from "@/components/Snippet";
|
||||
import { name } from "eslint-plugin-prettier/recommended";
|
||||
|
||||
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)]
|
||||
---
|
||||
|
||||
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.
|
||||
|
||||
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 ?" %}
|
||||
|
||||
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 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.
|
||||
</Callout>
|
||||
|
||||
## 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 :
|
||||
|
||||
{% tabs defaultSelectedTab="jsx" %}
|
||||
|
||||
{% 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 %}
|
||||
<tabs.reactReducerExample />
|
||||
|
||||
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.
|
||||
|
||||
{% 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 :
|
||||
<tabs.reactReducerWhySpreadOperator />
|
||||
|
||||
{% snippet path="react/reducer/reducer-why-spread-operator.jsx" language="jsx" showLineNumbers=true /%}
|
||||
|
||||
On perdrait ici la propriété `message` si on ne la déversait pas dans le nouvel état.
|
||||
|
||||
{% /callout %}
|
||||
On perdrait ici la propriété `message` si on ne la déversait pas dans le nouvel état.
|
||||
</Callout>
|
||||
|
||||
## 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` :
|
||||
|
||||
```js
|
||||
import { useReducer } from "react";
|
||||
```
|
||||
<tabs.reactUseReducerImport />
|
||||
|
||||
Ensuite, on va définir notre état initial :
|
||||
|
||||
{% tabs defaultSelectedTab="js" %}
|
||||
|
||||
{% 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 %}
|
||||
<tabs.reactReducerInitialState />
|
||||
|
||||
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 %}
|
||||
<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.
|
||||
|
||||
{% tab value="ts" label="TypeScript" %}
|
||||
{% snippet path="react/reducer/reducer.ts" language="ts" showLineNumbers=true /%}
|
||||
{% /tab %}
|
||||
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.
|
||||
|
||||
{% /tabs %}
|
||||
|
||||
{% 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.
|
||||
|
||||
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.
|
||||
|
||||
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 %}
|
||||
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>
|
||||
|
||||
Enfin, on peut utiliser le hook useReducer dans notre composant :
|
||||
|
||||
{% tabs defaultSelectedTab="js" %}
|
||||
|
||||
{% 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 %}
|
||||
<tabs.reactUseReducerUsage />
|
||||
|
||||
`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 :
|
||||
|
||||
{% snippet path="react/reducer/reducer-dispatch-increment.js" language="js" /%}
|
||||
<tabs.reactDispatchIncrement />
|
||||
|
||||
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.
|
||||
|
||||
{% 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" %}
|
||||
|
||||
{% 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 %}
|
||||
<tabs.reactActionsEnum />
|
||||
</Callout>
|
||||
|
||||
### 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 :
|
||||
|
||||
{% snippet path="react/reducer/reducer-actions-union.ts" language="ts" /%}
|
||||
<tabs.reactActionsUnion />
|
||||
|
||||
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
|
||||
|
||||
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" %}
|
||||
|
||||
{% 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 %}
|
||||
<tabs.reactActionCreator />
|
||||
|
||||
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
|
||||
|
||||
@ -236,64 +169,36 @@ Pour t'aider à mieux comprendre le fonctionnement du hook `useReducer` et comme
|
||||
|
||||
### Fichier counterReducer.js ou counterReducer.ts
|
||||
|
||||
{% tabs defaultSelectedTab="js" %}
|
||||
|
||||
{% 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 %}
|
||||
<tabs.reactFileCounterReducer />
|
||||
|
||||
### Fichier Counter.jsx ou Counter.tsx
|
||||
|
||||
{% tabs defaultSelectedTab="jsx" %}
|
||||
|
||||
{% 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 %}
|
||||
<tabs.reactFileCounterComponent />
|
||||
|
||||
## 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
|
||||
- **B** - Pour des états complexes ou des états qui dépendent les uns des autres
|
||||
</Callout>
|
||||
|
||||
- **A** - Pour des états simples
|
||||
- **B** - Pour des états complexes ou des états qui dépendent les uns des autres
|
||||
<Callout type="question" title="Quelle est la signature d'un reducer ?">
|
||||
- **A** - `(state, action) => { /* ... */ }`
|
||||
- **B** - `(action, state) => { /* ... */ }`
|
||||
- **C** - `(state) => { /* ... */ }`
|
||||
- **D** - `(action) => { /* ... */ }`
|
||||
</Callout>
|
||||
|
||||
{% /callout %}
|
||||
<Callout type="question" title="Pourquoi déverser le contenu de l'état actuel dans le nouvel état ?">
|
||||
- **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
|
||||
</Callout>
|
||||
|
||||
{% callout type="question" title="Quelle est la signature d'un reducer ?" %}
|
||||
|
||||
- **A** - `(state, action) => { /* ... */ }`
|
||||
- **B** - `(action, state) => { /* ... */ }`
|
||||
- **C** - `(state) => { /* ... */ }`
|
||||
- **D** - `(action) => { /* ... */ }`
|
||||
|
||||
{% /callout %}
|
||||
|
||||
{% callout type="question" title="Pourquoi déverser le contenu de l'état actuel dans le nouvel état ?" %}
|
||||
|
||||
- **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
|
||||
|
||||
{% /callout %}
|
||||
|
||||
{% callout type="question" title="Pourquoi utiliser des constantes pour les types d'actions ?" %}
|
||||
|
||||
- **A** - Pour rendre le code plus lisible
|
||||
- **B** - Pour alourdir inutillement le code
|
||||
- **C** - Pour éviter de se tromper dans le type de l'action
|
||||
|
||||
{% /callout %}
|
||||
<Callout type="question" title="Pourquoi utiliser des constantes pour les types d'actions ?">
|
||||
- **A** - Pour rendre le code plus lisible
|
||||
- **B** - Pour alourdir inutillement le code
|
||||
- **C** - Pour éviter de se tromper dans le type de l'action
|
||||
</Callout>
|
||||
|
||||
## 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