ReactJS+NodeJS

React: Intoduction

1.Introduction,istallation

Components

2.a>Components 2.b> Constructeur et propriétés 2.c> Components:Exemples

State,filter , map ...

4.a> State (data) 4.b> State (change data) 4.c> State (Formulaire)
Exercice 1:Vente Produit Exercice 2:Note Stagiaire Exercice 3:Quizz Exercice 4:Gestion matchs Exercice 5:Crud Produit

Props

5a.Props introduction Exercice 1

Exercices

6.a Nombre Random 6.b Game Pile ou Face 6.c Calculatrice 6.c Quizz 6.c Les Styles Dynamiques 6.c Array Object Filter

..

7.React Hooks

Exercices

Exercice1: Client Crud Exercice2 :Filter Teams Exercice3 : Multi-select

Props dans Composant fonctionnel

Exemples Exercice1 Exercice2 Exercice3

Routage

7.Routage 8.Routage :public and restricted

Axios ,Fetch, Api

CRUD application

Redux,Redux Toolkit

Cours Redux

Exercices Redux

Exercice1 Social App Exercice1 WhatsApp App Exercice2 Restaurant App Exercice3 Student App Exercice4 Income ,Expense App Exercice5 Bank App

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

folder Projet: test_react_project

Redux est un module qui permet de gérer les states de chaque components dans une seule state Globale

Redux se compose de:
  1. Store: :créer une seule State regroupant les state de toutes les components
  2. Reducer :un objet contenant:
    1. le State locale d'une component
    2. Les fonctions (Actions) qui manipule le state locale
Installation du Redux
npm install redux react-redux
Le redux contient les fichiers suivant:actions.js,reducers.js,store.js
actions.js
Rôle : Définit les actions, qui sont des objets JavaScript avec un type et éventuellement une charge utile. Les actions représentent les intentions de modifier l'état de l'application.
Exemple :
// actions.js
export const increment = () => ({
  type: 'INCREMENT',
});
reducers.js
Rôle : Définit le reducer, une fonction pure qui prend l'état actuel et une action, puis renvoie le nouvel état. Le reducer spécifie comment l'état de l'application change en réponse à une action donnée.
Exemple :
// reducers.js
const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    default:
      return state;
  }
};
store.js
Rôle : Crée le store Redux, qui détient l'état global de l'application. Il est configuré avec le reducer principal (ou combiné) et peut être utilisé pour dispatch des actions, accéder à l'état global et s'abonner à des changements d'état.
Exemple :
// store.js
import { createStore } from 'redux';
import counterReducer from './reducers';

const store = createStore(counterReducer);
dispatch
Rôle : La méthode dispatch est fournie par le store et est utilisée pour envoyer des actions au reducer. Elle informe au store quelle action doit être traitée.
Exemple :
// dispatch d'une action
store.dispatch(increment());
Provider (de react-redux)
Rôle : Un composant React qui enveloppe l'application, fournissant ainsi le store à tous les composants enfants via le contexte React. Cela permet aux composants de lire l'état du store et de dispatch des actions.
Exemple :
// index.js
import { Provider } from 'react-redux';
import store from './redux/store';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
Exemple:Book, ajouter, Afficher
actions.js
 export const  addBook=(book)=>({
type:"ajouter",
payload:book
})
reducer.js
const initialState={
    listeBooks:[]
}

const BookReducer=(state=initialState,action)=>
{
    switch(action.type)
    {
        case 'ajouter':
            return({
                ...state,
                listeBooks:[...state.listeBooks,action.payload]
            }
            )

        break;
        default :return (state)
    }
}
export default BookReducer;
store.js
import {createStore} from 'redux'
import BookReducer from './reducer';
  const store=createStore(BookReducer);
export default store;
index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './ReduxBook/store';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
 <React.StrictMode>
   <App />
 </React.StrictMode>
 </Provider>
);
reportWebVitals();
AjouterBook.js

 import { useState } from "react"
  import { useDispatch, useSelector } from "react-redux"
  import { addBook } from "../ReduxBook/actions";

export default function AjouterBook(){
    const [book,setBook]=useState({id:Date.now(),titre:""})
    const [message,setMessage]=useState("")
      const Dispatch=useDispatch();
    const addBooks=()=>{
        if(book.titre!="")
        {
              Dispatch(addBook(book))
            setMessage("Bien Ajouté")
        }
        else
        {
            setMessage("Erreur Non Ajouté")

        }

    }
    return(<div>
      titre :<input type="text" name="titre" onChange={(event)=>setBook({...book,titre:event.target.value})} />
      <input type="button" onClick={addBooks} value="Add"/>
      {message}
        </div>)
}
ListeBooks.js

 import { useState } from "react"
import { useSelector } from "react-redux"

export default function ListeBooks()
{
     //récupéer les données from bookReducer tableau listebooks
    const listeBooks=useSelector((state)=>state.listeBooks);
    return (<div>
        liste Books 
        <table>
            <thead>
                <th>Id</th>
                <th>Titre</th>
            </thead>
            <tbody>
                {listeBooks.map((b)=>{
                    return <tr>
                        <td>{b.id}</td>
                        <td>{b.titre}</td>
                        </tr>
                })}
            </tbody>
        </table>
    </div>)
}
app.js
import React from "react";
import { BrowserRouter,Routes,Route,Link } from "react-router-dom";
import AjouterBook from "./BookComponents/AjouterBooks";
import ListeBooks from "./BookComponents/ListeBooks";
export default function App()
{
  return (
<BrowserRouter> <Link to="/AjouterBook">Ajouter Book</Link> <Link to="/listeBooks">Liste Books</Link> <Routes> <Route path="/AjouterBook" element={<AjouterBook />}/> <Route path="/listeBooks" element={<ListeBooks/>}/> </Routes> </BrowserRouter> </div>) }
Exercice
Veuillez ajouter les Actions modifier et supprimer un Book

Exemples:Crud produit
actions.js
// src/redux/actions.js
export const addProduct = (product) => ({
  type: 'ADD_PRODUCT',
  payload: product,
});

export const updateProduct = (id, updatedProduct) => ({
  type: 'UPDATE_PRODUCT',
  payload: { id, updatedProduct },
});

export const deleteProduct = (id) => ({
  type: 'DELETE_PRODUCT',
  payload: id,
});
reducers.js

 // src/redux/reducers.js
const initialState = {
  products: [
    { id: 1, libelle: 'Produit 1', prix: 10, quantite: 5 },
    { id: 2, libelle: 'Produit 2', prix: 20, quantite: 10 },
    // ... d'autres produits
  ],
};

const productReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_PRODUCT':
      return {
        ...state,
        products: [...state.products, action.payload],
      };
    case 'UPDATE_PRODUCT':
      return {
        ...state,
        products: state.products.map((product) =>
          product.id === action.payload.id ? action.payload.updatedProduct : product
        ),
      };
    case 'DELETE_PRODUCT':
      return {
        ...state,
        products: state.products.filter((product) => product.id !== action.payload),
      };
    default:
      return state;
  }
};

export default productReducer;

 
store.js

 // src/redux/store.js
import { createStore } from 'redux';
import productReducer from './reducers';

const store = createStore(productReducer);

export default store;

 
index.js

 // src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>,
  document.getElementById('root')
);

 
App.js

 // src/App.js
import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addProduct, updateProduct, deleteProduct } from './redux/actions';

function App() {
  const products = useSelector((state) => state.products);
  const dispatch = useDispatch();
  const [newProduct, setNewProduct] = useState({ libelle: '', prix: 0, quantite: 0 });

  const handleAddProduct = () => {
    dispatch(addProduct({ ...newProduct, id: Date.now() }));
    setNewProduct({ libelle: '', prix: 0, quantite: 0 });
  };

  const handleUpdateProduct = (id, updatedProduct) => {
    dispatch(updateProduct(id, updatedProduct));
  };

  const handleDeleteProduct = (id) => {
    dispatch(deleteProduct(id));
  };

  return (
    <div>
      <h1>Liste des Produits</h1>
      <ul>
        {products.map((product) => (
          <li key={product.id}>
            {product.libelle} - {product.prix} - {product.quantite}
            <button onClick={() => handleUpdateProduct(product.id, { ...product, quantite: product.quantite + 1 })}>
              Augmenter Quantité
            </button>
            <button onClick={() => handleDeleteProduct(product.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
      <h2>Ajouter un Produit</h2>
      <label>Libellé: </label>
      <input
        type="text"
        value={newProduct.libelle}
        onChange={(e) => setNewProduct({ ...newProduct, libelle: e.target.value })}
      />
      <br />
      <label>Prix: </label>
      <input
        type="number"
        value={newProduct.prix}
        onChange={(e) => setNewProduct({ ...newProduct, prix: Number(e.target.value) })}
      />
      <br />
      <label>Quantité: </label>
      <input
        type="number"
        value={newProduct.quantite}
        onChange={(e) => setNewProduct({ ...newProduct, quantite: Number(e.target.value) })}
      />
      <br />
      <button onClick={handleAddProduct}>Ajouter</button>
    </div>
  );
}

export default App;

 
Exemple 2
actions.js

// src/redux/actions.js
// Définition des actions
export const ADD_TASK = 'ADD_TASK';
export const UPDATE_TASK = 'UPDATE_TASK';
export const DELETE_TASK = 'DELETE_TASK';

// Action creators
export const addTask = (task) => ({
  type: ADD_TASK,
  payload: task,
});

export const updateTask = (id, updatedTask) => ({
  type: UPDATE_TASK,
  payload: { id, updatedTask },
});

export const deleteTask = (id) => ({
  type: DELETE_TASK,
  payload: id,
});
reducers.js

// src/redux/reducers.js
// Définition du reducer
const initialState = {
  tasks: [],
};

const taskReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_TASK':
      return {
        ...state,
        tasks: [...state.tasks, action.payload],
      };
    case 'UPDATE_TASK':
      return {
        ...state,
        tasks: state.tasks.map((task) =>
          task.id === action.payload.id ? action.payload.updatedTask : task
        ),
      };
    case 'DELETE_TASK':
      return {
        ...state,
        tasks: state.tasks.filter((task) => task.id !== action.payload),
      };
    default:
      return state;
  }
};

export default taskReducer;
store.js

// src/redux/store.js
// Configuration du store
import { createStore } from 'redux';
import taskReducer from './reducers';

const store = createStore(taskReducer);

export default store;
index.js

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>,
  document.getElementById('root')
);
App.js

// src/App.js
import React, { useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addTask, updateTask, deleteTask } from './redux/actions';

function App() {
  // Utilisation de useSelector pour accéder à l'état du store
  const tasks = useSelector((state) => state.tasks);
  const dispatch = useDispatch();
  const [newTask, setNewTask] = useState({ id: 1, title: '' });

  // Dispatch des actions pour effectuer des opérations CRUD
  const handleAddTask = () => {
    dispatch(addTask({ ...newTask, id: Date.now() }));
    setNewTask({ id: 1, title: '' });
  };

  const handleUpdateTask = (id, updatedTask) => {
    dispatch(updateTask(id, updatedTask));
  };

  const handleDeleteTask = (id) => {
    dispatch(deleteTask(id));
  };

  return (
    <div>
      <h1>Liste des Tâches</h1>
      <ul>
        {tasks.map((task) => (
          <li key={task.id}>
            {task.title}
            <button onClick={() => handleUpdateTask(task.id, { ...task, title: 'Updated Task' })}>
              Mettre à jour
            </button>
            <button onClick={() => handleDeleteTask(task.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
      <h2>Ajouter une Tâche</h2>
      <label>Titre: </label>
      <input
        type="text"
        value={newTask.title}
        onChange={(e) => setNewTask({ ...newTask, title: e.target.value })}
      />
      <br />
      <button onClick={handleAddTask}>Ajouter</button>
    </div>
  );
}

export default App;
Redux avec api
Dans cet exemple on va utliser json-server avec le fichier db.js suivant:

// db.json
{
  "tasks": [
    { "id": 1, "title": "Faire les courses" },
    { "id": 2, "title": "Apprendre React" },
    { "id": 3, "title": "Préparer le dîner" }
  ]
}
lancer le serveur backend:

json-server --watch db.json --port 3004
actions.js

// src/redux/actions.js
export const FETCH_TASKS = 'FETCH_TASKS';
export const ADD_TASK = 'ADD_TASK';
export const DELETE_TASK = 'DELETE_TASK';

export const fetchTasks = (tasks) => ({
  type: FETCH_TASKS,
  payload: tasks,
});

export const addTask = (task) => ({
  type: ADD_TASK,
  payload: task,
});

export const deleteTask = (id) => ({
  type: DELETE_TASK,
  payload: id,
});
reducers.js

// src/redux/reducers.js
import { FETCH_TASKS, ADD_TASK, DELETE_TASK } from './actions';

const initialState = {
  tasks: [],
};

const taskReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_TASKS:
      return { ...state, tasks: action.payload };
    case ADD_TASK:
      return { ...state, tasks: [...state.tasks, action.payload] };
    case DELETE_TASK:
      return { ...state, tasks: state.tasks.filter((task) => task.id !== action.payload) };
    default:
      return state;
  }
};

export default taskReducer;
store.js
// src/redux/store.js
import { createStore } from 'redux';
import taskReducer from './reducers';

const store = createStore(taskReducer);

export default store;
index.js

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>,
  document.getElementById('root')
);
App.js
// src/redux/store.js
// src/App.js
import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchTasks, addTask, deleteTask } from './redux/actions';
import axios from 'axios';

const apiUrl = 'http://localhost:3001/tasks';

const App = () => {
  const tasks = useSelector((state) => state.tasks);
  const dispatch = useDispatch();
  const [newTask, setNewTask] = useState('');

  useEffect(() => {
    // Chargement initial des tâches depuis l'API
    axios.get(apiUrl).then((response) => dispatch(fetchTasks(response.data)));
  }, [dispatch]);

  const handleAddTask = () => {
    // Ajout d'une nouvelle tâche à l'API
    axios.post(apiUrl, { title: newTask }).then((response) => {
      dispatch(addTask({ title: newTask }));
      setNewTask('');
    });
  };

  const handleDeleteTask = (id) => {
    // Suppression d'une tâche de l'API
    axios.delete(`${apiUrl}/${id}`).then(() => {
      dispatch(deleteTask(id));
    });
  };

  return (
    <div>
      <h1>Liste des Tâches</h1>
      <ul>
        {tasks.map((task) => (
          <li key={task.id}>
            {task.title}
            <button onClick={() => handleDeleteTask(task.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
      <h2>Ajouter une Tâche</h2>
      <label>Titre: </label>
      <input
        type="text"
        value={newTask}
        onChange={(e) => setNewTask(e.target.value)}
      />
      <br />
      <button onClick={handleAddTask}>Ajouter</button>
    </div>
  );
};

export default App;
Exemple 2:Getion des commande
CRUD Client:
CRUD Produits:
CRUD Commandes:

Créez le fichier clientActions.js :


// src/redux/clientActions.js
export const FETCH_CLIENTS = 'FETCH_CLIENTS';
export const ADD_CLIENT = 'ADD_CLIENT';
export const DELETE_CLIENT = 'DELETE_CLIENT';
export const UPDATE_CLIENT = 'UPDATE_CLIENT';

export const fetchClients = (clients) => ({
  type: FETCH_CLIENTS,
  payload: clients,
});

export const addClient = (client) => ({
  type: ADD_CLIENT,
  payload: client,
});

export const deleteClient = (id) => ({
  type: DELETE_CLIENT,
  payload: id,
});

export const updateClient = (id, updatedClient) => ({
  type: UPDATE_CLIENT,
  payload: { id, updatedClient },
});
Créez le fichier clientReducer.js :

// src/redux/clientReducer.js
import { FETCH_CLIENTS, ADD_CLIENT, DELETE_CLIENT, UPDATE_CLIENT } from './clientActions';

const initialState = {
  clients: [],
};

const clientReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_CLIENTS:
      return { ...state, clients: action.payload };
    case ADD_CLIENT:
      return { ...state, clients: [...state.clients, action.payload] };
    case DELETE_CLIENT:
      return { ...state, clients: state.clients.filter((client) => client.id !== action.payload) };
    case UPDATE_CLIENT:
      return {
        ...state,
        clients: state.clients.map((client) =>
          client.id === action.payload.id ? action.payload.updatedClient : client
        ),
      };
    default:
      return state;
  }
};

export default clientReducer;
Créez le fichier produitActions.js :


// src/redux/produitActions.js
export const FETCH_PRODUITS = 'FETCH_PRODUITS';
export const ADD_PRODUIT = 'ADD_PRODUIT';
export const DELETE_PRODUIT = 'DELETE_PRODUIT';
export const UPDATE_PRODUIT = 'UPDATE_PRODUIT';

export const fetchProduits = (produits) => ({
  type: FETCH_PRODUITS,
  payload: produits,
});

export const addProduit = (produit) => ({
  type: ADD_PRODUIT,
  payload: produit,
});

export const deleteProduit = (id) => ({
  type: DELETE_PRODUIT,
  payload: id,
});

export const updateProduit = (id, updatedProduit) => ({
  type: UPDATE_PRODUIT,
  payload: { id, updatedProduit },
});
Créez le fichier produitReducer.js :


// src/redux/produitReducer.js
import { FETCH_PRODUITS, ADD_PRODUIT, DELETE_PRODUIT, UPDATE_PRODUIT } from './produitActions';

const initialState = {
  produits: [],
};

const produitReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_PRODUITS:
      return { ...state, produits: action.payload };
    case ADD_PRODUIT:
      return { ...state, produits: [...state.produits, action.payload] };
    case DELETE_PRODUIT:
      return { ...state, produits: state.produits.filter((produit) => produit.id !== action.payload) };
    case UPDATE_PRODUIT:
      return {
        ...state,
        produits: state.produits.map((produit) =>
          produit.id === action.payload.id ? action.payload.updatedProduit : produit
        ),
      };
    default:
      return state;
  }
};

export default produitReducer;
Créez le fichier commandeActions.js :

// src/redux/commandeActions.js
export const FETCH_COMMANDES = 'FETCH_COMMANDES';
export const ADD_COMMANDE = 'ADD_COMMANDE';
export const DELETE_COMMANDE = 'DELETE_COMMANDE';
export const UPDATE_COMMANDE = 'UPDATE_COMMANDE';

export const fetchCommandes = (commandes) => ({
  type: FETCH_COMMANDES,
  payload: commandes,
});

export const addCommande = (commande) => ({
  type: ADD_COMMANDE,
  payload: commande,
});

export const deleteCommande = (id) => ({
  type: DELETE_COMMANDE,
  payload: id,
});

export const updateCommande = (id, updatedCommande) => ({
  type: UPDATE_COMMANDE,
  payload: { id, updatedCommande },
});
Créez le fichier commandeReducer.js :

// src/redux/commandeReducer.js
import { FETCH_COMMANDES, ADD_COMMANDE, DELETE_COMMANDE, UPDATE_COMMANDE } from './commandeActions';

const initialState = {
  commandes: [],
};

const commandeReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_COMMANDES:
      return { ...state, commandes: action.payload };
    case ADD_COMMANDE:
      return { ...state, commandes: [...state.commandes, action.payload] };
    case DELETE_COMMANDE:
      return { ...state, commandes: state.commandes.filter((commande) => commande.id !== action.payload) };
    case UPDATE_COMMANDE:
      return {
        ...state,
        commandes: state.commandes.map((commande) =>
          commande.id === action.payload.id ? action.payload.updatedCommande : commande
        ),
      };
    default:
      return state;
  }
};

export default commandeReducer;
Créez le fichier store.js :


// src/redux/store.js
import { createStore, combineReducers } from 'redux';
import clientReducer from './clientReducer';
import produitReducer from './produitReducer';
import commandeReducer from './commandeReducer';

// Combinez les réducteurs
const rootReducer = combineReducers({
  clients: clientReducer,
  produits: produitReducer,
  commandes: commandeReducer,
});

// Créez le store avec les réducteurs combinés
const store = createStore(rootReducer);

export default store;
Créez le fichier AjouterClient.js :

// src/components/AjouterClient.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { addClient } from '../redux/clientActions';

const AjouterClient = () => {
  const dispatch = useDispatch();
  const [newClient, setNewClient] = useState({ id: '', nom: '' });

  const handleAddClient = () => {
    dispatch(addClient(newClient));
    setNewClient({ id: '', nom: '' });
  };

  return (
    <div>
      <h2>Ajouter un Client</h2>
      <label>Nom: </label>
      <input
        type="text"
        value={newClient.nom}
        onChange={(e) => setNewClient({ ...newClient, nom: e.target.value })}
      />
      <br />
      <button onClick={handleAddClient}>Ajouter</button>
    </div>
  );
};

export default AjouterClient;
Créez le fichier AfficherListeClients.js :

// src/components/AfficherListeClients.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { deleteClient } from '../redux/clientActions';

const AfficherListeClients = ({ onEdit }) => {
  const clients = useSelector((state) => state.clients.clients);
  const dispatch = useDispatch();

  const handleDeleteClient = (id) => {
    dispatch(deleteClient(id));
  };

  return (
    <div>
      <h2>Liste des Clients</h2>
      <ul>
        {clients.map((client) => (
          <li key={client.id}>
            {client.nom}
            <button onClick={() => onEdit(client.id, client.nom)}>Modifier</button>
            <button onClick={() => handleDeleteClient(client.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default AfficherListeClients;
Créez le fichier ModifierClient.js :

// src/components/ModifierClient.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { updateClient } from '../redux/clientActions';

const ModifierClient = ({ id, currentNom, onClose }) => {
  const dispatch = useDispatch();
  const [updatedNom, setUpdatedNom] = useState(currentNom);

  const handleUpdateClient = () => {
    dispatch(updateClient(id, { nom: updatedNom }));
    onClose();
  };

  return (
    <div>
      <h2>Modifier un Client</h2>
      <label>Nom: </label>
      <input
        type="text"
        value={updatedNom}
        onChange={(e) => setUpdatedNom(e.target.value)}
      />
      <br />
      <button onClick={handleUpdateClient}>Modifier</button>
      <button onClick={onClose}>Annuler</button>
    </div>
  );
};

export default ModifierClient;
Créez le fichier AjouterProduit.js :

// src/components/AjouterProduit.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { addProduit } from '../redux/produitActions';

const AjouterProduit = () => {
  const dispatch = useDispatch();
  const [newProduit, setNewProduit] = useState({ id: '', nom: '', prix: '' });

  const handleAddProduit = () => {
    dispatch(addProduit(newProduit));
    setNewProduit({ id: '', nom: '', prix: '' });
  };

  return (
    <div>
      <h2>Ajouter un Produit</h2>
      <label>Nom: </label>
      <input
        type="text"
        value={newProduit.nom}
        onChange={(e) => setNewProduit({ ...newProduit, nom: e.target.value })}
      />
      <br />
      <label>Prix: </label>
      <input
        type="text"
        value={newProduit.prix}
        onChange={(e) => setNewProduit({ ...newProduit, prix: e.target.value })}
      />
      <br />
      <button onClick={handleAddProduit}>Ajouter</button>
    </div>
  );
};

export default AjouterProduit;
Créez le fichier AfficherListeProduits.js :

// src/components/AfficherListeProduits.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { deleteProduit } from '../redux/produitActions';

const AfficherListeProduits = ({ onEdit }) => {
  const produits = useSelector((state) => state.produits.produits);
  const dispatch = useDispatch();

  const handleDeleteProduit = (id) => {
    dispatch(deleteProduit(id));
  };

  return (
    <div>
      <h2>Liste des Produits</h2>
      <ul>
        {produits.map((produit) => (
          <li key={produit.id}>
            {produit.nom} - Prix: {produit.prix}
            <button onClick={() => onEdit(produit.id, produit.nom)}>Modifier</button>
            <button onClick={() => handleDeleteProduit(produit.id)}>Supprimer</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default AfficherListeProduits;
Créez le fichier ModifierProduit.js :

// src/components/ModifierProduit.js
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { updateProduit } from '../redux/produitActions';

const ModifierProduit = ({ id, currentNom, currentPrix, onClose }) => {
  const dispatch = useDispatch();
  const [updatedNom, setUpdatedNom] = useState(currentNom);
  const [updatedPrix, setUpdatedPrix] = useState(currentPrix);

  const handleUpdateProduit = () => {
    dispatch(updateProduit(id, { nom: updatedNom, prix: updatedPrix }));
    onClose();
  };

  return (
    <div>
      <h2>Modifier un Produit</h2>
      <label>Nom: </label>
      <input
        type="text"
        value={updatedNom}
        onChange={(e) => setUpdatedNom(e.target.value)}
      />
      <br />
      <label>Prix: </label>
      <input
        type="text"
        value={updatedPrix}
        onChange={(e) => setUpdatedPrix(e.target.value)}
      />
      <br />
      <button onClick={handleUpdateProduit}>Modifier</button>
      <button onClick={onClose}>Annuler</button>
    </div>
  );
};

export default ModifierProduit;
Créez le fichier AjouterCommande.js :

// src/components/AjouterCommande.js
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addCommande } from '../redux/commandeActions';

const AjouterCommande = () => {
  const dispatch = useDispatch();
  const [newCommande, setNewCommande] = useState({ id: '', listeProduit: [], client: '' });

  // Récupérez la liste des clients et des produits depuis le state global
  const clients = useSelector((state) => state.clients.clients);
  const produits = useSelector((state) => state.produits.produits);

  const handleAddCommande = () => {
    dispatch(addCommande(newCommande));
    setNewCommande({ id: '', listeProduit: [], client: '' });
  };

  return (
    <div>
      <h2>Ajouter une Commande</h2>
      <label>Client: </label>
      <select
        value={newCommande.client}
        onChange={(e) => setNewCommande({ ...newCommande, client: e.target.value })}
      >
        <option value="">Sélectionner un client</option>
        {clients.map((client) => (
          <option key={client.id} value={client.id}>
            {client.nom}
          </option>
        ))}
      </select>
      <br />
      <label>Produits: </label>
      <select
        multiple
        value={newCommande.listeProduit}
        onChange={(e) => setNewCommande({ ...newCommande, listeProduit: Array.from(e.target.selectedOptions, (option) => option.value) })}
      >
        {produits.map((produit) => (
          <option key={produit.id} value={produit.id}>
            {produit.nom} - Prix: {produit.prix}
          </option>
        ))}
      </select>
      <br />
      <button onClick={handleAddCommande}>Ajouter</button>
    </div>
  );
};

export default AjouterCommande;
Créez le fichier ListeCommandes.js :

// src/components/ListeCommandes.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { deleteCommande } from '../redux/commandeActions';
import { Link } from 'react-router-dom';

const ListeCommandes = () => {
  const commandes = useSelector((state) => state.commandes.commandes);
  const dispatch = useDispatch();

  const handleDeleteCommande = (id) => {
    dispatch(deleteCommande(id));
  };

  return (
    <div>
      <h2>Liste des Commandes</h2>
      <ul>
        {commandes.map((commande) => (
          <li key={commande.id}>
            Commande #{commande.id} - Client: {commande.client} - Produits: {commande.listeProduit.join(', ')}
            <button onClick={() => handleDeleteCommande(commande.id)}>Supprimer</button>
            <Link to={`/modifier-commande/${commande.id}`}>
              <button>Modifier</button>
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default ListeCommandes;
Créez le fichier ModifierCommande.js :

// src/components/ModifierCommande.js
import React, { useState, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { updateCommande } from '../redux/commandeActions';

const ModifierCommande = ({ match, history }) => {
  const commandeId = match.params.id;
  const dispatch = useDispatch();

  const [updatedCommande, setUpdatedCommande] = useState({
    id: '',
    listeProduit: [],
    client: '',
  });

  // Récupérez la liste des clients et des produits depuis le state global
  const clients = useSelector((state) => state.clients.clients);
  const produits = useSelector((state) => state.produits.produits);
  const commandes = useSelector((state) => state.commandes.commandes);

  // Récupérez la commande actuelle en fonction de l'ID de la commande
  useEffect(() => {
    const currentCommande = commandes.find((commande) => commande.id === parseInt(commandeId));
    setUpdatedCommande(currentCommande || { id: '', listeProduit: [], client: '' });
  }, [commandeId, commandes]);

  const handleUpdateCommande = () => {
    dispatch(updateCommande(updatedCommande.id, updatedCommande));
    history.push('/liste-commandes');
  };

  return (
    <div>
      <h2>Modifier une Commande</h2>
      <label>Client: </label>
      <select
        value={updatedCommande.client}
        onChange={(e) => setUpdatedCommande({ ...updatedCommande, client: e.target.value })}
      >
        <option value="">Sélectionner un client</option>
        {clients.map((client) => (
          <option key={client.id} value={client.id}>
            {client.nom}
          </option>
        ))}
      </select>
      <br />
      <label>Produits: </label>
      <select
        multiple
        value={updatedCommande.listeProduit}
        onChange={(e) =>
          setUpdatedCommande({
            ...updatedCommande,
            listeProduit: Array.from(e.target.selectedOptions, (option) => option.value),
          })
        }
      >
        {produits.map((produit) => (
          <option key={produit.id} value={produit.id}>
            {produit.nom} - Prix: {produit.prix}
          </option>
        ))}
      </select>
      <br />
      <button onClick={handleUpdateCommande}>Modifier</button>
    </div>
  );
};

export default ModifierCommande;
Créer la component App.js

// src/App.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
import AjouterClient from './components/AjouterClient';
import AfficherListeClients from './components/AfficherListeClients';
import SupprimerClient from './components/SupprimerClient';
import ModifierClient from './components/ModifierClient';
import AjouterProduit from './components/AjouterProduit';
import AfficherListeProduits from './components/AfficherListeProduits';
import ModifierProduit from './components/ModifierProduit';
import AjouterCommande from './components/AjouterCommande';
import ListeCommandes from './components/ListeCommandes';
import ModifierCommande from './components/ModifierCommande';

const App = () => {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            {/* Clients */}
            <li><Link to="/ajouter-client">Ajouter un client</Link></li>
            <li><Link to="/liste-clients">Liste des clients</Link></li>

            {/* Produits */}
            <li><Link to="/ajouter-produit">Ajouter un produit</Link></li>
            <li><Link to="/liste-produits">Liste des produits</Link></li>

            {/* Commandes */}
            <li><Link to="/ajouter-commande">Ajouter une commande</Link></li>
            <li><Link to="/liste-commandes">Liste des commandes</Link></li>
          </ul>
        </nav>

        <Switch>
          {/* Clients */}
          <Route path="/ajouter-client" component={AjouterClient} />
          <Route path="/liste-clients" component={AfficherListeClients} />
          <Route path="/supprimer-client/:id" component={SupprimerClient} />
          <Route path="/modifier-client/:id" component={ModifierClient} />

          {/* Produits */}
          <Route path="/ajouter-produit" component={AjouterProduit} />
          <Route path="/liste-produits" component={AfficherListeProduits} />
          <Route path="/modifier-produit/:id" component={ModifierProduit} />

          {/* Commandes */}
          <Route path="/ajouter-commande" component={AjouterCommande} />
          <Route path="/liste-commandes" component={ListeCommandes} />
          <Route path="/modifier-commande/:id" component={ModifierCommande} />

          {/* Page d'accueil ou autre */}
          <Route path="/" component={() => <div>Accueil de l'application</div>} />
        </Switch>
      </div>
    </Router>
  );
};

export default App;
// src/components/ListeCommandeClient.js

// src/components/ListeCommandeClient.js
import React, { useState, useEffect } from 'react';
import { useSelector } from 'react-redux';

const ListeCommandeClient = () => {
  const [selectedClientId, setSelectedClientId] = useState('');
  const clients = useSelector((state) => state.clients.clients);
  const commandes = useSelector((state) => state.commandes.commandes);
  const produits = useSelector((state) => state.produits.produits);

  const selectedClient = clients.find((client) => client.id === selectedClientId);

  const handleClientChange = (e) => {
    setSelectedClientId(e.target.value);
  };

  const calculateTotal = (listeProduit) => {
    return listeProduit.reduce((total, produitId) => {
      const produit = produits.find((p) => p.id === produitId);
      return total + (produit ? produit.prix : 0);
    }, 0);
  };

  useEffect(() => {
    setSelectedClientId('');
  }, [clients]);

  return (
    <div>
      <h2>Liste des Commandes par Client</h2>
      <label>Sélectionner un client: </label>
      <select value={selectedClientId} onChange={handleClientChange}>
        <option value="">Sélectionner un client</option>
        {clients.map((client) => (
          <option key={client.id} value={client.id}>
            {client.nom}
          </option>
        ))}
      </select>

      {selectedClientId && (
        <div>
          <h3>Commandes de {selectedClient.nom}</h3>
          <ul>
            {commandes
              .filter((commande) => commande.client === selectedClientId)
              .map((commande) => (
                <li key={commande.id}>
                  Commande #{commande.id} - Total: {calculateTotal(commande.listeProduit)} €
                </li>
              ))}
          </ul>
          <p>Total à payer pour {selectedClient.nom}: {calculateTotal(commandes.filter((commande) => commande.client === selectedClientId).flatMap(commande => commande.listeProduit))} €</p>
        </div>
      )}
    </div>
  );
};

export default ListeCommandeClient;
// src/components/ProduitStatistiques.js

// src/components/ProduitStatistiques.js
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';

const ProduitStatistiques = () => {
  const commandes = useSelector((state) => state.commandes.commandes);
  const produits = useSelector((state) => state.produits.produits);

  const [statistiques, setStatistiques] = useState([]);

  useEffect(() => {
    const produitStatistiques = produits.map((produit) => {
      const quantiteTotaleVendue = commandes.reduce((total, commande) => {
        return (
          total +
          commande.listeProduit.filter((produitId) => produitId === produit.id).length
        );
      }, 0);

      const chiffreAffaires = commandes.reduce((total, commande) => {
        return (
          total +
          commande.listeProduit
            .filter((produitId) => produitId === produit.id)
            .reduce((sousTotal, produitId) => {
              const produit = produits.find((p) => p.id === produitId);
              return sousTotal + (produit ? produit.prix : 0);
            }, 0)
        );
      }, 0);

      return {
        produit,
        quantiteTotaleVendue,
        chiffreAffaires,
      };
    });

    setStatistiques(produitStatistiques);
  }, [commandes, produits]);

  return (
    <div>
      <h2>Statistiques des Produits</h2>
      <ul>
        {statistiques.map((statistique) => (
          <li key={statistique.produit.id}>
            {statistique.produit.nom} - Quantité totale vendue: {statistique.quantiteTotaleVendue} -
            Chiffre d'affaires: {statistique.chiffreAffaires} €
          </li>
        ))}
      </ul>
    </div>
  );
};

export default ProduitStatistiques;
// src/components/TopClientParTotaleCommande.js

// src/components/TopClientParTotaleCommande.js
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';

const TopClientParTotaleCommande = () => {
  const commandes = useSelector((state) => state.commandes.commandes);
  const clients = useSelector((state) => state.clients.clients);

  const [topClients, setTopClients] = useState([]);

  useEffect(() => {
    const clientMontantTotal = clients.map((client) => {
      const montantTotal = commandes
        .filter((commande) => commande.client === client.id)
        .reduce((total, commande) => {
          return total + commande.listeProduit.reduce((sousTotal, produitId) => {
            const produit = state.produits.find((p) => p.id === produitId);
            return sousTotal + (produit ? produit.prix : 0);
          }, 0);
        }, 0);

      return {
        client,
        montantTotal,
      };
    });

    const sortedTopClients = clientMontantTotal
      .sort((a, b) => b.montantTotal - a.montantTotal)
      .slice(0, 3);

    setTopClients(sortedTopClients);
  }, [commandes, clients]);

  return (
    <div>
      <h2>Top 3 Clients par Montant Total d'Achat</h2>
      <ul>
        {topClients.map((topClient) => (
          <li key={topClient.client.id}>
            {topClient.client.nom} - Montant Total d'Achat: {topClient.montantTotal} €
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TopClientParTotaleCommande;
toolkit react-redux

Installation: Redux

npm install @reduxjs/toolkit react-redux

Exemple1

reducers/PostReducer.js
import { createSlice } from '@reduxjs/toolkit'

//la valeur initiale de l'objet state.post
const initialState = {  name:'post content',  likes:0}
//le reducer contenant des fonctions slice permettant de
export const PostReducer = createSlice({
    name: 'post',
    initialState,
    reducers: {
        //Action1
      like: (state) => {
        state.likes+=1
      },
     //Action2
      dislike: (state) => {
        state.likes-=1
      },
      changerName: (state, action) => {
        state.name=action.payload  //récupérer la valeur envoyer par le distapcher
      },
    },
})

// Action creators are generated for each case reducer function
export const { like,dislike,changerName } = PostReducer.actions

export default PostReducer.reducer

Store/store.js
import { configureStore } from '@reduxjs/toolkit'
import PostReducer from '../reducers/PostReducer'

//store contient la State Globale de l'application
export const store = configureStore({
  reducer: {
    //nom de l'objet du state (state.post):le reducer qui traite cet variable
    post:PostReducer
   
  },
})
Components/PostComponent.js
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import {like} from '../reducers/PostReducer'
export default function PostComponent()
{
    //appler le state post du store
    const post=useSelector((state)=>state.post)

    const dispatch=useDispatch();
    const likeMe=()=>{
      dispatch(like())
    }

    return (
        <div>
          Le nom :{post.name} <br/>
          Nbre likes:{post.likes}
          <button onClick={likeMe} >Like</button>    
        </div>
    )
}
Components/TestComponent.js
import React, { useState } from "react"
import { useDispatch,useSelector } from "react-redux"
import {changerName} from '../reducers/PostReducer'
export default function TestComponent()

{
    //récupéer la valeur actuelle de l'attribut name de la variable du state post
    const post=useSelector((state)=>state.post)
    //on peut créer des variables de state mais ne sont pas ajouté dans le Store
    const [name,setName]=useState(post.name)

    const dispatch=useDispatch();
    const changerPostName=(e)=>{
        dispatch(changerName(e.target.value))
        }
    return   (
        <div>
            <input type="text"  defaultValue={name} onChange={changerPostName}/>
        </div>
    )
}
App.js
import logo from './logo.svg';
import './App.css';
import PostComponent from './components/PostComponent';
import TestComponent from './components/TestComponent';


function App() {
  return (
    <div className="App">
     
    <PostComponent />
    <TestComponent />
     
    </div>
  );
}

export default App;

index.js
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import { store } from './store/store'
import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
 <App />
  </Provider>,
  document.getElementById('root')
)