On va construire un chat entièrement fonctionnel 😱
Pas de panique on va y aller étape par étape, ce soir on commence par pouvoir envoyer un message en utilisant redux.
On verra demain pour qu'on puisse nous répondre, tant pis si on parle tout seul pendant quelque temps 😄
On part au plus simple pour commencer, on peaufinera ensuite ;)
On doit pouvoir
- Saisir un message dans le champ du bas
- On doit pouvoir soumettre ce message
- Il doit apparaître dans la liste des messages au-dessus, avec un nom d'auteur par défaut
Bien sûr tu dois utiliser redux et react-redux pour gérer tes données et tes actions
- Tout est dit ⬆️
Quelques pistes
Objectif : construire la ChatRoom
1 - Config: Récupération des outils et de la config
- On récupère le modèle
- On installe les dépendances
2 - Render: Instanciation du composant racine et rendu dans le DOM réel
- On vérifie qu'on fait bien le rendu d'un élément React dans le DOM avec le
render
de ReactDom
3 - Découpage: dans le composant racine on identifie les zones principales de l'appli
- On peut nommer le composant racine
App
ouChat
(ou autre au choix), il contiendra un listing de messages et une zone de formulaire
4 - Composants: reponsables de la représentation d'un fragment d'interface
- On décrit un composant
Form
pour le formulaire - On décrit un composant
Messages
pour le listing des messages - On décrit un composant
Message
pour le contenu d'un message
5 - Props: configuration des composants via les props
- Le composant
Messages
transpose une liste de messages vers une représentation.- On prépare un tableau de messages bidons pour tester (par exemple dans le composant racine) et on le passe via les props au composant
- Dans le composant on récupère les props, on les valide et on s'en sert pour instancier un
Message
par message du tableau
- Le composant
Message
transpose une chaîne de caractère représentant un message vers une représentation- On passe une prop à l'instanciation des
Message
dansMessages
- Dans le composant on récupère la prop, on la valide et on s'en sert
- On passe une prop à l'instanciation des
6 - Store: détenteur de la vérité
-
On installe Redux
-
On crée le store, le gardien du state, pour cela aide-toi du code produit en cours dans le dossier
store
-
Solution pour créer le store
import { createStore } from 'redux'; import reducer from 'chemin/vers/reducer'; const store = createStore(reducer); export default store;
-
Reducer: fonction pour qui sait retourner un nouveau state en fonction d'une action
- On crée le reducer à fournir au store, pour le moment il ne gère aucune action, pour cela aide-toi du reducer codé en cours
-
State initial: données représentant l'état initial de notre application
- Il nous faut la liste des messages initiaux dans le state
-
Solution pour créer le reducer
const initialState = { /* ranger les messages initiaux dans le state */ }; const reducer = (state = initialState, action = {}) => { switch (action.type) { default: return state; } } export default reducer;
7 - Provider: diffuseur du store
- Notre store est notre interface pour dialoguer avec le state, on le veut partout
- On installe React-Redux
- On instancie le composant
Provider
à la racine de notre application, on passe le composant racine en enfant du provider - On importe le store pour la passer en prop au provider
- Pense toujours à regarder les exemples du jour
8 - Container - mapStateToProps : branchement en lecture
-
On ne passe plus la listes des messages à l'instanciation de
Messages
-
On a d'un côté le store avec notre state contenant la liste des messages, de l'autre notre composant
Messages
prêt à recevoir les messages, on passe les infos de l'un à l'autre via le container -
Comme toujours va voir le code du jour pour retrouver comment utiliser
connect
fourni par react-redux pour créer ton container -
On n'oublie pas d'instancier le container et pas directement le composant
-
Exemple d'un container
// on importe connect et notre composant import { connect } from 'react-redux'; import MonComposant from 'src/components/MonComposant'; // on prépare une fonction qui reçoit le state et retourne un objet de props const mapStateToProps = (state) => ({ uneProp: state.uneInfo, }); // on aura peut-être par la suite besoin de dispatch mais pas pour l'instant const mapDispatchToProps = () => ({}); // on exporte ce que nous renvoie connect, c'est à dire le composant enrichi de props // on passe à connect nos fonctions pour préparer les objets de props puis le composant export default connect(mapStateToProps, mapDispatchToProps)(MonComposant);
Notre application sait afficher correctement des messages, il faut maintenant pouvoir en ajouter, on prépare un champ contrôlé puis on gère la soumission du formulaire
On fait en sorte que la value
du champ de notre composant Form
dépende du state
- On définit une valeur initiale dans notre state initial
- On reprend l'étape 8 pour créer une container pour le formulaire
- On reçoit une prop pour la valeur du champ dans le composant
Form
, on s'en sert
Puis il faut pouvoir modifier la valeur de ce champ, pour cela on passe à l'étape 9
9 - Containers - mapDispatchToProps : émission d'intentions
- Event: dans les composants on réagit à des interactions
-
On ajoute un écouteur via une prop
onClick
,onSubmit
,onChange
, ... dans le composant -
Un peu d'aide
// mon composant const Composant = () => { const handleChange = (event) => { console.log(event.value); // Ici j'ai l'intention de changer la valeur du champ } return ( <form> <input onChange={handleChange} /> </form> ); };
-
Oui mais quoi faire quand l'event à lieu ? on va émettre une intention ⬇️
-
- Dispatch d'une Action: émission d'une intention
-
Via mapDispatchToProps dans le container on passe une fonction en prop au composant
-
On commence avec un
console.log
dans cette fonction pour voir si tout va bien -
On reçoit cette fonction dans le composant via les props, on l'execute dans notre handler
-
Une fois qu'on a correctement vu notre message en console en réponse à l'évenement, on va dispatcher l'action
-
on prépare l'action type et l'action creator qui vont bien
-
Un exemple ?
const ACTION_TYPE = 'ACTION TYPE'; const actionCreator = (payload) => ({ type: ACTION_TYPE, payload });
-
dans le container on importe l'action creator, on s'en sert pour créer l'objet action et on dispatch
-
Un exemple ?
const mapStateToProps = (dispatch) => ({ uneProp: (unParam) => { const action = actionCreator(unParam); dispatch(action); } });
-
L'intention est émise, plus qu'à la traduire dans les faits
-
- Reducer = un traducteur d'intentions
-
Dispatcher, c'est appeler la méthode dispatch du store. On fait donc travailler notre store qui va appeler le reducer et lui passer l'action pour savoir comment le state doit évoluer
-
On ajoute un
case
dans notre reducer pour gérer le cas de cette action et décrire comment devra évoluer le state en fonction de l'action -
On n'oublie pas d'importer l'action type qui va bien
-
Un exemple ?
const reducer = (state = initialState, action = {}) => { switch (action.type) { case ACTION_TYPE: return { ...state, modif: 'truc', } default: return state; } };
-
On reprend l'étape 9 pour gérer la soumission