Exercices

LocalStorage Weather Api ToDo et LocalStorage

React+ionic

Ionic Create project 4.React Outils utiles 5.Lifecycle Methods 6.JSX

Gestion Ventes

Produit CRUD

6.Form :Ajouter un produit 8.Liste produits 9.Pagination 10.Liste produits +Pagination 11.Liste produits +Datatable 11.Liste produits +load more 12.Supprimer un produit 14.Details d'un produit 15.Recherche et Autocomplete

Reacts:Utils

Gestion des erreurs Variables d'environment Cookies Internationalization proptypes Form validation React Animation Fragment Google Maps

Utilisateur CRUD

18.Inscription upload file 19.Connexion et Les sessions 19.Connexion: JWT Token

Ventes CRUD

17.Vendre un produit 18.Facture Generate PDF 19.Statisques Charts

Redux





Redux ,Thunk Crud api

Thunk le middleware Redux Thunk est utilisé pour permettre aux actions de Redux d'être des fonctions plutôt que des objets.
Ces fonctions sont appelées "thunks". Le middleware Redux Thunk intercepte ces fonctions avant qu'elles n'atteignent les Reducers,
leur permettant d'effectuer des opérations asynchrones avant de déclencher les actions appropriées.
Action simple
 
const fetchUser = (userId) => ({
  type: 'FETCH_USER',
  payload: userId,
});
une fois on appelle cette action on envoie (userId) au reducer qui exécute l'action puis retourne les résultats
Supposons maintenant que les données du user sont récupéré à partir d'une api
 
const fetchUser = (userId) => ({
    function (){
    axios.get("http://localhost:3004/users/"+userId).then((res)=>{   
   type: 'FETCH_USER',
  payload: res.data,	 
    })}
  
});
Erreur car l'action doit retouner un objet et non une fonction
objet:
{
	type:"",
	payload:"",
	data1:"",
	...
}
donc afin de retourné une fonction dans l'action on doit créer un Thunk action au lieu de action simple:
 // Thunk action creator
const fetchUser = (userId) => {
  return (dispatch, getState) => {
    axios.get(`http://localhost:3004/users/${userId}`)
      .then((res) => {
        // appeler l'action du reducer
        dispatch({
          type: 'FETCH_USER',
          payload: res.data,
        });
      })
      .catch((error) => {
        // si Erreur appler l'action  FETCH_USER_FAILURE du reducer
        dispatch({
          type: 'FETCH_USER_FAILURE',
          payload: error.message,
        });
      });
  };
};
Remarque
Dans un projet CRUD pour une API on doit utiliser Redux et thunk Action
Exemples:Clients Crud
Afin d'exécuter les Requests http on a besoin d'un serveur backEnd on peut créer un serveur de test à l'aide de json-server
npm install -g json-server
npm install json-server
json-server --watch db.json --port 3004
Le fichier db.json est Crée changer le contenu de ce fichier à:
{"clients": [{
    "id": 1,
    "name": "nom1",
    "email": "email1@gm"
}]}
puis relancer le serveur
json-server --watch db.json --port 3004

Remarque: Si vous avez une erreur veuillez lancer la commande suivante:

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process
json-server --watch db.json --port 3004
Installer Axios
le module Axios de React pour consommer les Rest Apis crées dans nodeJs project
npm install axios --save
installer redux-thunk
npm install redux-thunk
Créer le fichier redux_api_thunk/redux/clientActions.js
 // clientActions.js
export const getClients = (clients) => ({ 
type: "GET_CLIENTS",
 payload: clients });
export const errorGetClient = (error) => ({ 
type: "Error_GET_CLIENTS",
 payload: error });
Créer le fichier redux_api_thunk/redux/clientThunk.js
//clientThunk.js
 import axios from 'axios';
import {
  getClients,
  errorGetClient,
  
} from './clientActions';

export const getClients_thunk = () => {
  return async (dispatch) => {
    try {
      const response = await axios.get('http://localhost:3004/clients');
      dispatch(getClients(response.data));
    } catch (error) {
      dispatch(errorGetClient(error.message));
    }
  };
};
Créer le fichier redux_api_thunk/redux/clientReducer.js
  const initialState = {
    clients: [],
    loading: false,
    error: null,
  };
  
  const clientReducer = (state = initialState, action) => {
    switch (action.type) {
      case "GET_CLIENTS":
        return { ...state,
		clients: action.payload, 
		loading: false,
		error: null };
		
     case "Error_GET_CLIENTS":
	 return { ...state,
		loading: false,
		error: action.payload };
 default:
        return state;
    }
  };
  
  export default clientReducer;
Créer le fichier redux_api_thunk/redux/store.js
import { createStore, applyMiddleware } from 'redux';
import {thunk} from 'redux-thunk';
import clientReducer from './clientReducer';

const store = createStore(clientReducer, applyMiddleware(thunk));

export default store;
App.js
// App.js
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getClients_thunk } from './redux_api_thunk/redux/clientsThunk';

const App = () => {
  const dispatch = useDispatch();
  const clients = useSelector((state) => state.clients);
  const loading = useSelector((state) => state.loading);
  const error = useSelector((state) => state.error);

  useEffect(() => {
    dispatch(getClients_thunk());
  }, [dispatch]);


  return (
    <div>
      <h1>Client Manager</h1>
      {loading && <p>Loading...</p>}
      {error && <p>Error: {error}</p>}
      <ul>
        {clients.map((client) => (
          <li key={client.id}>
            {client.name} ({client.email}){' '}
            <button onClick={() => handleDeleteClient(client.id)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import reportWebVitals from './reportWebVitals';
import store from './redux_api_thunk/redux/store'
import { Provider } from 'react-redux';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
  <React.StrictMode>
    <App />
  </React.StrictMode>
  </Provider>
);
reportWebVitals();
Tester
npm start
Ajouter les autres actions
// Clientctions.js
export const FETCH_CLIENTS_REQUEST = 'FETCH_CLIENTS_REQUEST';
export const FETCH_CLIENTS_SUCCESS = 'FETCH_CLIENTS_SUCCESS';
export const FETCH_CLIENTS_FAILURE = 'FETCH_CLIENTS_FAILURE';

export const ADD_CLIENT_REQUEST = 'ADD_CLIENT_REQUEST';
export const ADD_CLIENT_SUCCESS = 'ADD_CLIENT_SUCCESS';
export const ADD_CLIENT_FAILURE = 'ADD_CLIENT_FAILURE';

export const DELETE_CLIENT_REQUEST = 'DELETE_CLIENT_REQUEST';
export const DELETE_CLIENT_SUCCESS = 'DELETE_CLIENT_SUCCESS';
export const DELETE_CLIENT_FAILURE = 'DELETE_CLIENT_FAILURE';

export const fetchClientsRequest = () => ({ type: FETCH_CLIENTS_REQUEST });
export const fetchClientsSuccess = (clients) => ({ type: FETCH_CLIENTS_SUCCESS, payload: clients });
export const fetchClientsFailure = (error) => ({ type: FETCH_CLIENTS_FAILURE, payload: error });

export const addClientRequest = () => ({ type: ADD_CLIENT_REQUEST });
export const addClientSuccess = (client) => ({ type: ADD_CLIENT_SUCCESS, payload: client });
export const addClientFailure = (error) => ({ type: ADD_CLIENT_FAILURE, payload: error });

export const deleteClientRequest = () => ({ type: DELETE_CLIENT_REQUEST });
export const deleteClientSuccess = (clientId) => ({ type: DELETE_CLIENT_SUCCESS, payload: clientId });
export const deleteClientFailure = (error) => ({ type: DELETE_CLIENT_FAILURE, payload: error });
// Clienthunks.js
import axios from 'axios';
import {
  fetchClientsRequest,
  fetchClientsSuccess,
  fetchClientsFailure,
  addClientRequest,
  addClientSuccess,
  addClientFailure,
  deleteClientRequest,
  deleteClientSuccess,
  deleteClientFailure,
} from './clientActions';

const API_BASE_URL = 'http://localhost:3004/clients';

export const fetchClients = () => {
  return async (dispatch) => {
    dispatch(fetchClientsRequest());
    try {
      const response = await axios.get(API_BASE_URL);
      dispatch(fetchClientsSuccess(response.data));
    } catch (error) {
      dispatch(fetchClientsFailure(error.message));
    }
  };
};

export const addClient = (client) => {
  return async (dispatch) => {
    dispatch(addClientRequest());
    try {
      const response = await axios.post(API_BASE_URL, client);
      dispatch(addClientSuccess(response.data));
    } catch (error) {
      dispatch(addClientFailure(error.message));
    }
  };
};

export const deleteClient = (clientId) => {
  return async (dispatch) => {
    dispatch(deleteClientRequest());
    try {
      await axios.delete(`${API_BASE_URL}/${clientId}`);
      dispatch(deleteClientSuccess(clientId));
    } catch (error) {
      dispatch(deleteClientFailure(error.message));
    }
  };
};
// clientReducer.js
import {
    FETCH_CLIENTS_REQUEST,
    FETCH_CLIENTS_SUCCESS,
    FETCH_CLIENTS_FAILURE,
    ADD_CLIENT_REQUEST,
    ADD_CLIENT_SUCCESS,
    ADD_CLIENT_FAILURE,
    DELETE_CLIENT_REQUEST,
    DELETE_CLIENT_SUCCESS,
    DELETE_CLIENT_FAILURE,
  } from './clientActions';
  
  const initialState = {
    clients: [],
    loading: false,
    error: null,
  };
  
  const clientReducer = (state = initialState, action) => {
    switch (action.type) {
      case FETCH_CLIENTS_REQUEST:
      case ADD_CLIENT_REQUEST:
      case DELETE_CLIENT_REQUEST:
        return { ...state, loading: true, error: null };
  
      case FETCH_CLIENTS_SUCCESS:
        return { ...state, clients: action.payload, loading: false, error: null };
  
      case ADD_CLIENT_SUCCESS:
        return { ...state, clients: [...state.clients, action.payload], loading: false, error: null };
  
      case DELETE_CLIENT_SUCCESS:
        return {
          ...state,
          clients: state.clients.filter((client) => client.id !== action.payload),
          loading: false,
          error: null,
        };
  
      case FETCH_CLIENTS_FAILURE:
      case ADD_CLIENT_FAILURE:
      case DELETE_CLIENT_FAILURE:
        return { ...state, loading: false, error: action.payload };
  
      default:
        return state;
    }
  };
  
  export default clientReducer;