Présentation
Cette prise de notes a été réalisé pendant le suivi de la formation React JS + Redux pour débutants.
Réalisée pendant la formation : sans relecture …
Projet 1 - Netflix des Bandes Annonces
Comment choisir ses composants :
- Pas de règles, juste du bon sens et des questions,
- Est-ce que le composant est réutilisable ? Centralisation, Responsabilité, …
- Trouver le juste milieu,
Rappel :
- chaque fois que l’on met à jour
setState
, render est appelé, setState
est assynchrone,- Quand on appel un event, le scope this change. Il faut donc un bind (
this.handleChange = this.handleChange.bind(this);
), - Les
props
sont en lecture seule,
- chaque fois que l’on met à jour
Cycle de vie :
- Mounting (Création) :
constructor
: récupération des props et gestion du state,componentWillMount
: appel des services API, mise en place des données, etc…render
: génération du rendu,componentDidMount
: quand c’est fini,
- Update :
componentWillReceiveProps
: Avant que les props soient mis à jour,shoudlComponentUpdate
: permet de valider que le component doit effectivement se mettre à jour,componentWillUpdate
: le component va se mettre à jour,render
,componentDidUpdate
: le component a été mis à jour,
- Suppression :
componentWillUnmount
: le composant va être “démonté” !,componentDidUnmount
: le composant a été démonté.
- Mounting (Création) :
Axios :
npm install axios
,
Projet 2 - Intro Redux - Consultation d’utilosateurs
Reducers :
- Store : contient l’état (ou les états de l’application),
- Reducers : fonction dont le résultat alimente le store,
- Root Reducers : effectue le mappage entre le store et les différents reducers,
- IMPORTANT : TOUS les reducers sont appelés !
Container : les composants qui doivent connaître les changements de morceaux de state,
mapStateToProps
:- Tout ce qui est mis dans mapStateToProps est mis dans les props (le nom est clair mais pas obligatoire)
- En fait, il faudrait l’appeller
mapStoreToProps
car c’est bien le store complet qui est passé,
Mise à jour state :
- Création d’une action qui retourne le type et les données associées : le message,
- Appeler cette fonction toute seule ne sert à rien car le composant n’a que faire que de l’action.
- La cible de l’action c’est le reducer,
- C’est le rôle de la fonction
mapDispacthToProps
(le nom est libre) :- Elle prend en paramètre la fonction
dispatch
qui est la fonction Redux qui va appeler tous les reducers en leur passant en paramètre le résultat d’un autre appel, - Dans cette fonction, le principe est de retourner un objet qui sera également “ajouter” aux props du composant,
- Cette objet contient des fonctions qui retournent les actions qui doivent être passé à dispatch,
- Un “raccourci” : utiliser
bindActionCreators
qui “simplifient” la syntaxe, - Bon en fait, c’est plus d’actualité …
- Elle prend en paramètre la fonction
function mapDispatchToProps(dispatch) {
// selectUser est importé depuis ../action/index.js et pointé par la proprité du même nom
return bindActionCreators({selecteUser: selectUser}, dispatch);
// est l'équivalent (enfin je crois de )
return {
selectUser: (user) => {
dispatch(selectUser(user))
}
}
}
Projet 3 - Taux de change
Redux Thunk :
- https://github.com/reduxjs/redux-thunk,
- Permet de gérer plusieurs dispatch sur une seule action, de gérer de l’asynchrone, …
- Pour l’installer :
npm install redux-thunk
, - Pour le rendre dispo :
- Classique :
import thunk from "redux-thunk";
, - Faut l’ajouter comme “middleware” :
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
,
- Classique :
Petit exo perso : que la liste des pays soient dynamique :
Créer une action spécifique :
export function getSupportedCurrencies() {
return function(dispatch) {
// La base USD est importante pour que les pays EUR soient aussi ramenés
axios.get('https://api.exchangeratesapi.io/latest?base=USD')
.then(axiosResponse => {
dispatch({ type: GET_SUPPORTED_CURRENCIES, payload: axiosResponse.data.rates})
});
}
}
Créer le reducer associé :
import { GET_SUPPORTED_CURRENCIES } from "../actions";
const initialState = {
supportedCurrencies: []
}
export default function(state = initialState, action) {
switch (action.type) {
case GET_SUPPORTED_CURRENCIES:
return {
...state,
supportedCurrencies: getCodes(action.payload)
}
default:
return state;
}
}
function getCodes(data) {
return Object.keys(data).filter(c => c !== 'USD');
}
“Enregistrer” le reducer dans la liste :
import { combineReducers } from 'redux';
import ReducerCountries from "./reducer_countries";
import ReducerRateExchange from "./reducer_rate_exchange";
import ReducerSupportedCountries from "./reducer_supported_countries";
const rootReducer = combineReducers({
// Le nouveay
supportedCountriesReducer: ReducerSupportedCountries,
countriesReducer: ReducerCountries,
rateExchangeReducer: ReducerRateExchange
});
export default rootReducer;
Comme cela doit être chargé au “plus tôt”, j’ai mis cela dans le composant Apps,
componentDidMount() {
this.props.getSupportedCurrencies();
}
// [...]
const mapDispatchToProps = {
getSupportedCurrencies
}
export default connect(null, mapDispatchToProps)(App);
Maintenant, il faut que les valeurs soient disponibles dans l’autre reducer ce qui n’est pas “prévu”,
Mais via redux-thunk et la méthode getState c’est possible (semble-t-il). Donc dans l’action de récupération des pays :
export function fecthCountries() {
return function(dispatch, getState) { // Ajout de getState
axios.get('https://restcountries.eu/rest/v2/all')
.then((axiosResponse) => {
const supportedCurrencies = getState().supportedCountriesReducer.supportedCurrencies // Passage d'une information supplémentaire
dispatch({ type: GET_COUNTRIES, payload: axiosResponse.data, filter: supportedCurrencies })
});
}
}
Autres petits exos persos
- Pouvoir supprimer un pays : une action, ajout d’un cas dans le reducer, mapDispatchToProps, onClick …
- Un pays ne peut pas être ajouté deux fois,
- Un sélecteur par défaut.
Partie 4 - Boite à Post
Mise en place
- JSONWebServer :
- Casual :
React-Router
- https://reactrouter.com/,
npm install react-router
,- Import :
import { Router, Route, Link, browserHistory, IndexRoute } from "react-router";
- Router : balise principale pour la gestion des routes,
- Pour qu’elle puisse gérer l’history, il faut lui passer browserHistory sinon ca marche pas,
<Route path="/" component={PostList} />
,
- Route : permet de définir une route qui fait pointer un chemin (path) vers un component,
- ex :
<Route path="/" component={PostList} />
, - Avec un paramètre :
<Route path="post/:id" component={Post} />
,- Paramètre qui sont à disposition dans les props :
this.props.params.id
,
- Gestion d’une route par défaut ou d’erreur :
<Route path='*' component={NotFound} >
.
- ex :
- Router : balise principale pour la gestion des routes,
React-Transition-Group
React Redux Form
- https://redux-form.com,
- En très gros : permet de lier le store à un formulaire (en très gros :)),
npm install redux-form
,- Mise en place :
- Import :
import { reduxForm } from "redux-form";
, - Il faut ensuite créer la configuration du formulaire :
const formConfig = { form: 'createPostForm', // Nom du formulaire : obligatoire. Sert de clé pour le store fields: ['title', 'content', 'author'], // Les champs du formulaire validate: validate, // Pointeur de la fonction de validation initialValues: { author: 'Moi' } // Gestion de valeurs initiales };
- Import :
- Il faut ensuite “connecter” la configuration et le composant :
reduxForm(formConfig)(PostForm)
, - Puis, il faut utiliser la méthode
handleSubmit
de reduxform suite à la validation du formulaire :onSubmit={handleSubmit(this.createPost.bind(this))}
- Pour que cela fonctionne, il faut également réserver une entrée dans le store :
// [...] import { reducer as ReducerForm } from "redux-form";
- Il faut ensuite “connecter” la configuration et le composant :
const rootReducer = combineReducers({
posts: ReducerPosts,
activePost: ReducerActivePost,
form: ReducerForm
});