2

ReactJS(v18) | Zustand State Management Library | CRUD Example

 1 year ago
source link: https://www.learmoreseekmore.com/2022/10/reactjs-v18-zustand-state.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
ReactJS(v18)%20%20Zustand%20State%20Management%20Library%20%20CRUD%20Example.png

In this article, we will implement a ReactJs(v18) CRUD example by creating state management using the Zustand library.

Zustand:

The Zustand is a small, fast, and scalable state management library. It is straightforward to use and integrate. Some of its features are:
  • It contains hooks API, so it is very easy to consume in react applications.
  • Support for Async methods.
  • Easily integrate additional middleware like 'immer', 'devtools', etc
  • State can be accessed outside of the react components
  • Easily integrate along with other state management libraries like 'Redux' & 'React Context API'.

Create ReactJS Application:

Let's create a ReactJS Application to accomplish the demo.
npx create-react-app name-of-your-app

Configure React Bootstrap Library:

Let's install the React Bootstrap library.
npm install react-bootstrap bootstrap
Now add the bootstrap CSS file reference on 'index.js'.
import 'bootstrap/dist/css/bootstrap.min.css';

Create React Component 'Layout':

Now let's React component like 'Layout' inside of 'components/shared'(new folders). This 'Layout' component will be our master template where we can have a header and footer.
src/components/shared/Layou.js:


  1. import { Container } from "react-bootstrap";
  2. import Navbar from "react-bootstrap/Navbar";
  3. const Layout = ({ children }) => {
  4. return (
  5. <>
  6. <Navbar bg="primary" variant="dark">
  7. <Navbar.Brand>Cakes</Navbar.Brand>
  8. </Navbar>
  9. <Container>{children}</Container>
  10. </>
  11. export default Layout;
  • Here we configured the React Bootstrap Navbar component.

Render the 'Layout' component element in 'App.js'.

src/App.js:


  1. import "./App.css";
  2. import Layout from "./components/shared/Layout";
  3. function App() {
  4. return <Layout></Layout>;
  5. export default App;

Create React Component 'AllCakes':

Let's create a page-level react component like 'AllCakes' inside of 'pages' folder(new folder).
src/pages/AllCakes.js:


  1. const AllCakes = () => {
  2. return <></>;
  3. export default AllCakes;

Configure React Routing:

Install the 'react-router-dom' package.
npm i react-router-dom
Now configure the 'Routes' component in the 'App' component.
src/App.js:


  1. import { Route, Routes } from "react-router-dom";
  2. import "./App.css";
  3. import Layout from "./components/shared/Layout";
  4. import AllCakes from "./pages/AllCakes";
  5. function App() {
  6. return (
  7. <Layout>
  8. <Routes>
  9. <Route path="/" element={<AllCakes />}></Route>
  10. </Routes>
  11. </Layout>
  12. export default App;
  • Here home page route is configured to the 'AllCakes' component.

The 'BrowserRouter' component from 'react-router-dom' wrap around the 'App' element in 'index.js'

src/index.js:


  1. import React from "react";
  2. import ReactDOM from "react-dom/client";
  3. import "./index.css";
  4. import App from "./App";
  5. import "bootstrap/dist/css/bootstrap.min.css";
  6. import { BrowserRouter } from "react-router-dom";
  7. const root = ReactDOM.createRoot(document.getElementById("root"));
  8. root.render(
  9. <BrowserRouter>
  10. <App />
  11. </BrowserRouter>

Install Zustand Library:

Let's install our 'Zustand' state management library.
npm install zustand

Configure Store:

Let's try to configure a sample store. So let's create a folder like 'store' and then add a file like 'cakeStore.js'.
src/store/cakeStore.js:


  1. import create from "zustand";
  2. export const useCakeStore = create((set) => ({
  3. cakesData: [
  4. id: 1,
  5. name: "Red Velvet",
  6. cost: 120,
  7. imageUrl:
  8. "https://www.fnp.com/images/pr/l/v20220202161510/valentine-s-heart-red-velvet-cake_1.jpg",
  • (Line: 3) The 'create' method loads from the 'zustand' library. The 'set' input parameter helps to update the data into the state property.
  • (Line: 4) The 'cakeData' is my store state property. Here assigned some sample data.

Implement Read Operation(Read Dummy Data From Store):

Let's implement the read operation by fetching the sample data from our store(cakStore.js).
src/pages/AllCakes.js:


  1. import { Container,Row, Col,Card } from "react-bootstrap";
  2. import { useCakeStore } from "../store/cakeStore";
  3. const AllCakes = () => {
  4. const allCakes = useCakeStore((state) => state.cakesData);
  5. return (
  6. <>
  7. <Container className="mt-2">
  8. <Row xs={1} md={3} className="g-4">
  9. {allCakes.map((cake) => (
  10. <Col key={cake.id}>
  11. <Card>
  12. <Card.Img
  13. variant="top"
  14. src={cake.imageUrl}
  15. style={{ height: 400, width: "100%" }}
  16. />
  17. <Card.Body>
  18. <Card.Title>{cake.name}</Card.Title>
  19. <Card.Text>Price - {cake.cost}</Card.Text>
  20. </Card.Body>
  21. </Card>
  22. </Col>
  23. </Row>
  24. </Container>
  25. </>
  26. export default AllCakes;
  • (Line: 5) The 'useCakeStore' is our store hook created using the 'zustand' library. So here we passed the arrow function with store 'state' as the input parameter and returns any state property or state action(function). 
  • (Line: 10) Here looping our 'allCakes' variable that got data from our store.
1.JPG

Configure DevTools:

Using Zustand store management we can use the 'DevTools' to track the changes of state in our 'Redux' browser extension tool.
src/store/cakeStore.js:


  1. import create from "zustand";
  2. import { devtools } from "zustand/middleware";
  3. export const useCakeStore = create(
  4. devtools((set) => ({
  5. cakesData: [
  6. id: 1,
  7. name: "Red Velvet",
  8. cost: 120,
  9. imageUrl:
  10. "https://www.fnp.com/images/pr/l/v20220202161510/valentine-s-heart-red-velvet-cake_1.jpg",
  • (Line: 5) Add the 'devtools' that loads from the 'zustand/middleware'.
2.JPG

Setup JSON Server:

Let's setup the fake API by setting up the JSON server in our local machine.
Run the below command to install the JSON server globally onto your local machine.
npm install -g json-server
For our demo purpose go to the ReactJS application and add the following to the 'package.json' file. By default, the JSON server runs on port number 3000, ReactJS also runs on the same portal locally so here we specify another port number explicitly.
"json-server":"json-server --watch db.json --port 4000"
3.JPG
Now to invoke the above command run the following command in the ReactJS app root folder.
npm run json-server
After running the above command for the first time, a 'db.json' file gets created, so this file act as a database. So let's add some sample data to the file below.
4.JPG

Now access our fake JSON API at 'http://localhost:4000/cakes".

5.JPG

Install Axios Library:

Let's install the Axios library.
npm i axios

Implement Read Operation:

Let's implement the read operation by invoking the API and then saving the API response to the store and then fetching data from the store to our react component.
Using the Zustand store library we can invoke API calls in our store file 'cakeStore.js' as action methods.
src/store/cakeStore.js:


  1. import create from "zustand";
  2. import { devtools } from "zustand/middleware";
  3. import { immer } from "zustand/middleware/immer";
  4. import axios from "axios";
  5. export const useCakeStore = create(
  6. devtools(
  7. immer((set) => ({
  8. cakesData: [],
  9. getApi: async () => {
  10. const apiResponse = await axios.get("http://localhost:4000/cakes");
  11. set((state) => {
  12. state.cakesData = apiResponse.data;
  • (Line: 8) The 'immer' loads from the 'zustand/middleware/immer'. Here 'immer' helps to change the state data very easy way.
  • (Line: 10-15) Using zustand, we can async or nonasync methods directly into the store. Here 'getAPI' method invokes the API call to fetch data.
  • (Line: 12-14) Assigning the API response to our 'cakeData' state property.

Let's update our 'AllCakes' component.

src/pages/AllCakes.js:


  1. import { useEffect } from "react";
  2. import { Container, Row, Col, Card } from "react-bootstrap";
  3. import { useCakeStore } from "../store/cakeStore";
  4. const AllCakes = () => {
  5. const allCakes = useCakeStore((state) => state.cakesData);
  6. const callGetAPI = useCakeStore((state) => state.getApi);
  7. useEffect(() => {
  8. callGetAPI();
  9. }, []);
  10. return (
  11. <>
  12. <Container className="mt-2">
  13. <Row xs={1} md={3} className="g-4">
  14. {allCakes.map((cake) => (
  15. <Col key={cake.id}>
  16. <Card>
  17. <Card.Img
  18. variant="top"
  19. src={cake.imageUrl}
  20. style={{ height: 400, width: "100%" }}
  21. />
  22. <Card.Body>
  23. <Card.Title>{cake.name}</Card.Title>
  24. <Card.Text>Price - {cake.cost}</Card.Text>
  25. </Card.Body>
  26. </Card>
  27. </Col>
  28. </Row>
  29. </Container>
  30. </>
  31. export default AllCakes;
  • (Line: 7) Here we get the reference of our 'getAPI' method from our store.
  • (Line: 10) Invoking the Api call.
1.JPG

Create React Component 'AddCake.js':

Let's create a new React component like 'AddCake.js' in the 'pages' folder.
src/pages/AddCake.js:


  1. const AddCake = () => {
  2. return <></>;
  3. export default AddCake;

Configure the route for 'AddCake' component in the 'App' component

src/App.js:


  1. import { Route, Routes } from "react-router-dom";
  2. import "./App.css";
  3. import Layout from "./components/shared/Layout";
  4. import AddCake from "./pages/AddCake";
  5. import AllCakes from "./pages/AllCakes";
  6. function App() {
  7. return (
  8. <Layout>
  9. <Routes>
  10. <Route path="/" element={<AllCakes />}></Route>
  11. <Route path="/add-cake" element={<AddCake />}></Route>
  12. </Routes>
  13. </Layout>
  14. export default App;

Implement Create Operation:

Let's implement the create operation by creating a new item and also updating the new item data in the store.
Let's implement the create API call in 'cakeStore.js'.
src/store/cakeStore.js:


  1. import create from "zustand";
  2. import { devtools } from "zustand/middleware";
  3. import { immer } from "zustand/middleware/immer";
  4. import axios from "axios";
  5. export const useCakeStore = create(
  6. devtools(
  7. immer((set) => ({
  8. cakesData: [],
  9. getApi: async () => {
  10. const apiResponse = await axios.get("http://localhost:4000/cakes");
  11. set((state) => {
  12. state.cakesData = apiResponse.data;
  13. createCakeAPI: async (payload) => {
  14. const apiResponse = await axios.post(
  15. "http://localhost:4000/cakes",
  16. payload
  17. set((state) => {
  18. state.cakesData.push(apiResponse.data);
  • (Line: 16-24) The 'createCakeAPI' method invokes our post API and response data is saved into the store.

Let's implement the create operation logic in 'AddCake.js'.

src/pages/AddCake.js:


  1. import { useRef } from "react";
  2. import { Col, Container, Row, Form, Button } from "react-bootstrap";
  3. import { useNavigate } from "react-router-dom";
  4. import { useCakeStore } from "../store/cakeStore";
  5. const AddCake = () => {
  6. const name = useRef("");
  7. const imageUrl = useRef("");
  8. const cost = useRef("");
  9. const createAPICall = useCakeStore((state) => state.createCakeAPI);
  10. const navigate = useNavigate();
  11. const createHanlder = async () => {
  12. let payload = {
  13. name: name.current.value,
  14. imageUrl: imageUrl.current.value,
  15. cost: Number(cost.current.value)
  16. await createAPICall(payload);
  17. navigate("/");
  18. return (
  19. <>
  20. <Container className="mt-2">
  21. <Row>
  22. <Col className="col-md-8 offset-md-2">
  23. <legend>Create A New Cake</legend>
  24. <Form.Group className="mb-3" controlId="formName">
  25. <Form.Label>Name</Form.Label>
  26. <Form.Control type="text" ref={name} />
  27. </Form.Group>
  28. <Form.Group className="mb-3" controlId="formCost">
  29. <Form.Label>Cost</Form.Label>
  30. <Form.Control type="text" ref={cost} />
  31. </Form.Group>
  32. <Form.Group className="mb-3" controlId="formImageUrl">
  33. <Form.Label>Image URL</Form.Label>
  34. <Form.Control type="text" ref={imageUrl} />
  35. </Form.Group>
  36. <Button
  37. variant="primary"
  38. type="button"
  39. onClick={createHanlder}
  40. >Add</Button>
  41. </Col>
  42. </Row>
  43. </Container>
  44. </>
  45. export default AddCake;
  • (Line: 6-9) The 'useRef' variable is to read the form data.
  • (Line: 12) Get the reference of the create API call method from the store.
  • (Line: 15-23) The 'createHandler' method reads our form data and sends it to the create API call as payload.

Let's update our 'AllCakes' component as below.

src/page/AllCakes.js:


  1. import { useEffect } from "react";
  2. import { Container, Row, Col, Card, Button } from "react-bootstrap";
  3. import { useNavigate } from "react-router-dom";
  4. import { useCakeStore } from "../store/cakeStore";
  5. const AllCakes = () => {
  6. const allCakes = useCakeStore((state) => state.cakesData);
  7. const callGetAPI = useCakeStore((state) => state.getApi);
  8. const navigate = useNavigate();
  9. useEffect(() => {
  10. if (allCakes.length == 0) {
  11. callGetAPI();
  12. }, []);
  13. return (
  14. <>
  15. <Container className="mt-2">
  16. <Row>
  17. <Col className="col-md-4 offset-md-4">
  18. <Button
  19. variant="primary"
  20. type="button"
  21. onClick={() => navigate("/add-cake")}
  22. </Button>
  23. </Col>
  24. </Row>
  25. <Row xs={1} md={3} className="g-4">
  26. {allCakes.map((cake) => (
  27. <Col key={cake.id}>
  28. <Card>
  29. <Card.Img
  30. variant="top"
  31. src={cake.imageUrl}
  32. style={{ height: 400, width: "100%" }}
  33. />
  34. <Card.Body>
  35. <Card.Title>{cake.name}</Card.Title>
  36. <Card.Text>Price - {cake.cost}</Card.Text>
  37. </Card.Body>
  38. </Card>
  39. </Col>
  40. </Row>
  41. </Container>
  42. </>
  43. export default AllCakes;
  • (Line: 9) Declare the 'useNavigate()' variable.
  • (Line: 12-14) Here get API call only invokes if the data in the state is empty.
  • (Line: 21-27) The 'Add' button navigates to the 'AddCake' component.

(Step 1)

6.JPG

(Step 2)

7.JPG
(Step 3)
8.JPG

Create React Component 'EditCake':

Let's create a new react component like 'EditCake'.
src/pages/EditCake.js:


  1. const EditCake = () => {
  2. return <></>;
  3. export default EditCake;

Configure the route for the 'EditCake' component in the 'App' component.

src/App.js:


  1. import { Route, Routes } from "react-router-dom";
  2. import "./App.css";
  3. import Layout from "./components/shared/Layout";
  4. import AddCake from "./pages/AddCake";
  5. import AllCakes from "./pages/AllCakes";
  6. import EditCake from "./pages/EditCake";
  7. function App() {
  8. return (
  9. <Layout>
  10. <Routes>
  11. <Route path="/" element={<AllCakes />}></Route>
  12. <Route path="/add-cake" element={<AddCake />}></Route>
  13. <Route path="/edit-cake/:id" element={<EditCake />}></Route>
  14. </Routes>
  15. </Layout>
  16. export default App;

Implement Update Operation:

Let's implement the update operation to update an item and then update our zustand store.
Let's update the logic in the 'carStore.js' file.
src/store/carStore.js:


  1. import create from "zustand";
  2. import { devtools } from "zustand/middleware";
  3. import { immer } from "zustand/middleware/immer";
  4. import axios from "axios";
  5. export const useCakeStore = create(
  6. devtools(
  7. immer((set) => ({
  8. cakesData: [],
  9. getApi: async () => {
  10. const apiResponse = await axios.get("http://localhost:4000/cakes");
  11. set((state) => {
  12. state.cakesData = apiResponse.data;
  13. createCakeAPI: async (payload) => {
  14. const apiResponse = await axios.post(
  15. "http://localhost:4000/cakes",
  16. payload
  17. set((state) => {
  18. state.cakesData.push(apiResponse.data);
  19. updateCakeAPI: async (payload) => {
  20. const apiResponse = await axios.put(
  21. `http://localhost:4000/cakes/${payload.id}`,
  22. payload
  23. set((state) => {
  24. let cakeState = state.cakesData.filter((_) => _.id !== payload.id);
  25. cakeState.push(apiResponse.data);
  26. state.cakesData = cakeState;
  27. export const getcakeById = (id) => {
  28. return (state) => {
  29. let cake = state.cakesData.filter((c) => c.id === Number(id));
  30. if (cake) {
  31. return cake[0];
  32. return null;
  • (Line: 25-35) Invoking the update API call. Remove the old data of the item from the store and then push the API response into the store state.
  • (Line: 40-48) Here 'getCakeById' is our selector to get the item from the state by 'id' value. So this selector is used to fetch the item to edit and then bind it to our edit form.
src/pages/EditCake.js:


  1. import { useEffect } from "react";
  2. import { useNavigate, useParams } from "react-router-dom";
  3. import { getcakeById, useCakeStore } from "../store/cakeStore";
  4. import { useRef } from "react";
  5. import { Col, Container, Row, Form, Button } from "react-bootstrap";
  6. const EditCake = () => {
  7. const name = useRef("");
  8. const imageUrl = useRef("");
  9. const cost = useRef("");
  10. const { id } = useParams();
  11. const cakeToEdit = useCakeStore(getcakeById(id));
  12. const updateAPICall = useCakeStore((state) => state.updateCakeAPI);
  13. const navigate = useNavigate();
  14. useEffect(() => {
  15. if (cakeToEdit) {
  16. name.current.value = cakeToEdit.name;
  17. imageUrl.current.value = cakeToEdit.imageUrl;
  18. cost.current.value = cakeToEdit.cost;
  19. }, []);
  20. const updateHandle = async () => {
  21. let payload = {
  22. name: name.current.value,
  23. imageUrl: imageUrl.current.value,
  24. cost: Number(cost.current.value),
  25. id: Number(id),
  26. await updateAPICall(payload);
  27. navigate("/");
  28. return (
  29. <>
  30. <Container className="mt-2">
  31. <Row>
  32. <Col className="col-md-8 offset-md-2">
  33. <legend>Update A New Cake</legend>
  34. <Form.Group className="mb-3" controlId="formName">
  35. <Form.Label>Name</Form.Label>
  36. <Form.Control type="text" ref={name} />
  37. </Form.Group>
  38. <Form.Group className="mb-3" controlId="formCost">
  39. <Form.Label>Cost</Form.Label>
  40. <Form.Control type="text" ref={cost} />
  41. </Form.Group>
  42. <Form.Group className="mb-3" controlId="formImageUrl">
  43. <Form.Label>Image URL</Form.Label>
  44. <Form.Control type="text" ref={imageUrl} />
  45. </Form.Group>
  46. <Button variant="primary" type="button" onClick={updateHandle}>
  47. Update
  48. </Button>
  49. </Col>
  50. </Row>
  51. </Container>
  52. </>
  53. export default EditCake;
  • (Line: 7-9) Declared the 'useRef' variables to fetch the form data.
  • (Line: 10) Read the item to edit value from the URL using 'useParams'.
  • (Line: 11) Here we use our selector 'getCakeById' to fetch the item from the store state.
  • (Line: 12) Get the store action method reference that invokes the update API call.
  • (Line: 16-20) Populate the item to edit to our 'useRef' variables.
  • (Line: 23-32) The 'updateHandle' method consists of logic to invoke the update API call sending our form data as payload.

Now in the 'AllCake' component let's add the 'Edit' button.

src/pages/AllCake.js:


  1. <Card.Body>
  2. <Card.Title>{cake.name}</Card.Title>
  3. <Card.Text>Price - {cake.cost}</Card.Text>
  4. <Button
  5. variant="primary"
  6. onClick={() => navigate(`/edit-cake/${cake.id}`)}
  7. </Button>
  8. </Card.Body>

(Step 1)

9.JPG
(Step 2)
10.JPG
(Step 3)
11.JPG

Create React Component 'DeleteConfirmation':

Let's create a new react component like 'DeleteConfirmation' in the 'components/shared' folder.
src/components/shared/DeleteConfirmation.js:


  1. import Button from "react-bootstrap/Button";
  2. import Modal from "react-bootstrap/Modal";
  3. const DeleteConfirmation = (props) => {
  4. return (
  5. <>
  6. <Modal
  7. show={props.showModal}
  8. onHide={() => {
  9. props.closeDeleteConfirmationModalHandler();
  10. <Modal.Header closeButton>
  11. <Modal.Title>{props.title}</Modal.Title>
  12. </Modal.Header>
  13. <Modal.Body>{props.body}</Modal.Body>
  14. <Modal.Footer>
  15. <Button
  16. variant="secondary"
  17. onClick={() => {
  18. props.closeDeleteConfirmationModalHandler();
  19. Close
  20. </Button>
  21. <Button
  22. variant="danger"
  23. onClick={() => {
  24. props.confirmDeleteHandler();
  25. Confirm Delete
  26. </Button>
  27. </Modal.Footer>
  28. </Modal>
  29. </>
  30. export default DeleteConfirmation;
  • (Line:7) The 'show' property accepts the boolean value 'true' for display and 'false' for hiding modal.
  • (Line: 8-10) The 'onHide' event raises by the 'x' button(close button on top right corner). Registered with the parent component method like 'props.closeDeleteConfirmationModalHandler'.
  • (Line: 25-32) The 'Confirm Delete' button invokes the delete API call.

Implement Delete Operation:

Let's implement the delete API call in 'cakeStore.js'.
src/store/cakeStore.js:


  1. import create from "zustand";
  2. import { devtools } from "zustand/middleware";
  3. import { immer } from "zustand/middleware/immer";
  4. import axios from "axios";
  5. export const useCakeStore = create(
  6. devtools(
  7. immer((set) => ({
  8. cakesData: [],
  9. getApi: async () => {
  10. const apiResponse = await axios.get("http://localhost:4000/cakes");
  11. set((state) => {
  12. state.cakesData = apiResponse.data;
  13. createCakeAPI: async (payload) => {
  14. const apiResponse = await axios.post(
  15. "http://localhost:4000/cakes",
  16. payload
  17. set((state) => {
  18. state.cakesData.push(apiResponse.data);
  19. updateCakeAPI: async (payload) => {
  20. const apiResponse = await axios.put(
  21. `http://localhost:4000/cakes/${payload.id}`,
  22. payload
  23. set((state) => {
  24. let cakeState = state.cakesData.filter((_) => _.id !== payload.id);
  25. cakeState.push(apiResponse.data);
  26. state.cakesData = cakeState;
  27. deleteCakeAPI: async (id) => {
  28. const apiResponse = await axios.delete(
  29. `http://localhost:4000/cakes/${id}`
  30. set((state) => {
  31. state.cakesData = state.cakesData.filter((_) => _.id !== id);
  32. export const getcakeById = (id) => {
  33. return (state) => {
  34. let cake = state.cakesData.filter((c) => c.id === Number(id));
  35. if (cake) {
  36. return cake[0];
  37. return null;
  • (Line: 36-43) Delete API call. On API success item has to be removed from the store state as well.

src/pages/AllCakes.js:



  1. import { useEffect, useState } from "react";
  2. import { Container, Row, Col, Card, Button } from "react-bootstrap";
  3. import { useNavigate } from "react-router-dom";
  4. import DeleteConfirmation from "../components/shared/DeleteConfirmation";
  5. import { useCakeStore } from "../store/cakeStore";
  6. const AllCakes = () => {
  7. const allCakes = useCakeStore((state) => state.cakesData);
  8. const callGetAPI = useCakeStore((state) => state.getApi);
  9. const navigate = useNavigate();
  10. const [showModal, setShowModal] = useState(false);
  11. const [itemIdToDelete, setItemIdToDelete] = useState(0);
  12. const callDeleteAPI = useCakeStore((state) => state.deleteCakeAPI);
  13. useEffect(() => {
  14. if (allCakes.length == 0) {
  15. callGetAPI();
  16. }, []);
  17. const openDeleteConfirmationModalHandler = (id) => {
  18. setItemIdToDelete(id);
  19. setShowModal(true);
  20. const closeDeleteConfirmationModalHandler = () => {
  21. setItemIdToDelete(0);
  22. setShowModal(false);
  23. const confirmDeleteHandler = async () => {
  24. await callDeleteAPI(itemIdToDelete);
  25. setItemIdToDelete(0);
  26. setShowModal(false);
  27. return (
  28. <>
  29. <DeleteConfirmation
  30. showModal={showModal}
  31. title="Delete Confirmation"
  32. body="Are you sure to delete the item?"
  33. closeDeleteConfirmationModalHandler={
  34. closeDeleteConfirmationModalHandler
  35. confirmDeleteHandler={confirmDeleteHandler}
  36. ></DeleteConfirmation>
  37. <Container className="mt-2">
  38. <Row>
  39. <Col className="col-md-4 offset-md-4">
  40. <Button
  41. variant="primary"
  42. type="button"
  43. onClick={() => navigate("/add-cake")}
  44. </Button>
  45. </Col>
  46. </Row>
  47. <Row xs={1} md={3} className="g-4">
  48. {allCakes.map((cake) => (
  49. <Col key={cake.id}>
  50. <Card>
  51. <Card.Img
  52. variant="top"
  53. src={cake.imageUrl}
  54. style={{ height: 400, width: "100%" }}
  55. />
  56. <Card.Body>
  57. <Card.Title>{cake.name}</Card.Title>
  58. <Card.Text>Price - {cake.cost}</Card.Text>
  59. <Button
  60. variant="primary"
  61. onClick={() => navigate(`/edit-cake/${cake.id}`)}
  62. </Button>
  63. <Button
  64. variant="danger"
  65. type="button"
  66. onClick={() => {
  67. openDeleteConfirmationModalHandler(cake.id);
  68. >Delete</Button>
  69. </Card.Body>
  70. </Card>
  71. </Col>
  72. </Row>
  73. </Container>
  74. </>
  75. export default AllCakes;
  • (Line: 11) The 'useState' variable 'showModal' is used for displaying or hiding the modal
  • (Line: 12) The 'useState' variable 'itemIDToDelete' for holding the 'id' value of the item to be deleted.
  • (Line: 13) The 'callDeleteAPI' holds the delete API call method reference from the store.
  • (Line: 21-23) The 'openDeleteConfirmationModalHandler' method gets invoked to show the modal. Here we set value like  item 'id' to delete to 'itemIDToDelete' variable and 'true' value to 'showModal' variable.
  • (Line: 26-29) The 'closeDeleteConfirmationModalHandler' method gets invoke to hide the modal.
  • (Line: 31-35) The 'confirmDeleteHandler' invokes our delete API call.
12.JPG

Support Me!
Buy Me A Coffee PayPal Me

Video Session:

Wrapping Up:

Hopefully, I think this article delivered some useful information on the ReactJS(v18) CRUD sample using Zustand State Management Library. I love to have your feedback, suggestions, and better techniques in the comment section below.

Refer:

Follow Me:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK