Menu

React redux

Redux

Redux est un module de gestion du state de react

Il permet de mettre le state dans un store et le rend disponible dans tout les composant de l'application ce qui permet deviter de devoir passer tout nos etat par des props et de favoriser le SOC

Avec redux classique on a acces a 3 methodes

  • store.getState() : pour recuperer notre state dans notre application
  • store.dispatch({ ... }) : pour effectuer une action
  • store.subscribe(() => { ... }) : pour effectuer un rendu a chaque fois qu'une valeur du state change

Redux principe

Le module react-redux offre des hooks simplifier pour effecter la gestion du state

  • useSelector((state) => state.TRUC) : qui permet d'acceder directement a une valeur de notre state
  • useDispatch({ ... }) : qui permet d'effectuer une action

A chaque mise a jour du state, react-redux effectue un nouveau rendu

Redux communication

Mise en place de redux

Index de l'application react

Comme pour le module router-react-dom on englobe notre application react dans un Provider et on lui donne le store avec en paramettre

1import { BrowserRouter } from "react-router-dom"; 2import { createRoot } from "react-dom/client"; 3import { Provider } from "react-redux"; 4 5import App from "src/components/App"; 6import store from "src/store"; 7 8const rootReactElement = ( 9 <Provider store={store}> 10 <BrowserRouter> 11 <App /> 12 </BrowserRouter> 13 </Provider> 14); 15 16const root = createRoot(document.getElementById("root")); 17root.render(rootReactElement); 18

Index du store

Pour crée un store avec redux plusieurs elements sont necessaire

  • un state initial : qui determine notre state de base avant modification
  • des actions : qui permet de dire ce que l'on veux faire
  • un reducer : qui traduit nos actions et les interprete
  • des middlewares : qui permet defectuer des fonction asynchrone

Ici on crée notre store avec la fonction createStore et on lui donne en argument notre reducer et nos middlewares

1import { createStore, applyMiddleware, compose } from "redux"; 2 3import reducer from "src/store/reducers"; 4import dataMiddleware from "./middlewares/dataMiddleware"; 5import recipesMiddleware from "./middlewares/recipesMiddleware"; 6 7const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; 8 9const enhancers = composeEnhancers( 10 applyMiddleware(dataMiddleware, recipesMiddleware) 11); 12 13const store = createStore(reducer, enhancers); 14 15export default store; 16

Reducer

Ici si notre action est de type GET_DATA on retournera un nouveau state avec la key isLoading qui aura changer

  • initialState est le state par defaut au lancement de notre application
1import { GET_DATA } from "../actions/recipes"; 2 3export const initialState = { 4 list: [], 5 isLoading: true, 6 favorites: [], 7}; 8 9const reducer = (state = initialState, action = {}) => { 10 switch (action.type) { 11 case GET_DATA: 12 return { 13 // on copie tout le state actuel 14 ...state, 15 // on change la valeur qui nous interesse 16 isLoading: true, // ou action.isLoading par exemple 17 }; 18 19 default: 20 return state; 21 } 22}; 23 24export default reducer; 25

combineReducers

On peut utiliser combineReducers pour combiner plusieurs reducer

Les valeurs du state seront aussi separer :

  • Pour recuperer des valeur du state de recipes state.recipe.list
  • Pour recuperer des valeur du state de user state.user.email
1import { combineReducers } from "redux"; 2 3import recipesReducer from "./recipes"; 4import userReducer from "./user"; 5 6const rootReducer = combineReducers({ 7 recipes: recipesReducer, 8 user: userReducer, 9}); 10 11export default rootReducer; 12

Actions

Permet de mieux s'organier en utilisant des constantes et des fonction plutot que des string et des objet

1export const GET_DATA = "GET_DATA"; 2 3export const getData = () => ({ 4 type: GET_DATA, 5}); 6

Exemple

A chaque nouveau rendu on recupere toutes les données

1import { useEffect } from "react"; 2import { getData } from "src/store/actions/recipes"; 3 4import Menu from "src/components/Menu"; 5 6function App() { 7 useEffect(() => { 8 dispatch(getData()); 9 }, []); 10 11 return ( 12 <div className="app"> 13 <Menu /> 14 </div> 15 ); 16} 17 18export default App; 19

Middlewares

Permet de realiser des fonction asynchrone comme par exemple des requete a une API

Il aggisent comme des videurs chaqu'un a la suite des autres.

1// ... 2import dataMiddleware from "./middlewares/dataMiddleware"; 3import recipesMiddleware from "./middlewares/recipesMiddleware"; 4// ... 5const enhancers = composeEnhancers( 6 applyMiddleware( 7 dataMiddleware, // 1er middleware a agir 8 recipesMiddleware // 2nd a agir il aura acces au state mis a jour par le 1er 9 // etcetc autant de Mw que l'on veux 10 ) 11); 12 13const store = createStore(reducer, enhancers); 14 15export default store; 16

Redux middleware principe

A chaque rendu de l'application les Mw seront traverser

Si une action est capter dans un Mw une action sera effectuer et une nouvelle action sera créé a la suite

Redux requetes

Redux discussion

Utilisation

Les middleware utilise redux et pas react-redux on ne peut donc pas utiliser les hooks useSelector et useDispatch mais les methode du store de redux

A chaque fin d'action on next pour que le state evolue et ne reste pas figer

1import axios from "axios"; 2 3import { GET_DATA, getDataSuccess } from "../actions/recipes"; 4 5const dataMiddleware = (store) => (next) => (action) => { 6 switch (action.type) { 7 case GET_DATA: { 8 axios("http://localhost:8080/recipes") 9 .then((res) => { 10 store.dispatch(getDataSuccess(res.data)); 11 }) 12 .catch((error) => { 13 console.log(error); 14 }); 15 next(action); 16 break; 17 } 18 19 default: 20 next(action); 21 break; 22 } 23}; 24 25// equivalent 26 27// const dataMiddleware = (store) => { 28// return (next) => { 29// return (action) => { 30// // fait des truc 31// } 32// } 33// } 34 35export default dataMiddleware; 36

Selectos

Connect

Redux connect