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:- Store: :créer une seule State regroupant les state de toutes les components
-
Reducer :un objet contenant:
- le State locale d'une component
- Les fonctions (Actions) qui manipule le state locale
Installation du Redux
npm install redux react-redux
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.postconst initialState = { name:'post content', likes:0}//le reducer contenant des fonctions slice permettant deexport 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 functionexport 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'applicationexport 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'))
