Home > Software engineering >  How to call useEffect again on button click in react?
How to call useEffect again on button click in react?

Time:11-26

I am beginner in react. I am making a small project. How to add Product in cart and I am stuck at re Rendering useEffect. so what I want is to re Render the useEffect on button click. how do I do that?

Here Is my Cart Component

import React, { useContext, useEffect, useState,useCallback } from "react";
import { UserContext } from "./Context";
import { useHistory } from "react-router";
import cartImage from "../assets/man-shopping.png";
import Axios from "axios";

const Cart = () => {
  const { user, serUser } = useContext(UserContext);
  const history = useHistory();
  const [product, setProduct] = useState([]);

  const removeFromCart = (item) => {
    Axios.delete(`http://localhost:3002/cart/${item.Id}`).then((res) => {
      setProduct(
        product.filter((item) => {
          return item.Id !== res.data.Id;
        })
      );
    });
  };

  useEffect(() => {
    Axios.get(`http://localhost:3002/cart/${user.Id}`).then((res) => {
      setProduct(res.data);
    });
  }, [user]);


  return (
    <div
      className="d-flex align-items-center justify-content-center"
      style={{ height: "90vh" }}
    >
      {user.role === undefined ? (
        <div>
          <button
            className="btn btn-lg btn-primary bg-green"
            onClick={() => {
              history.push("/login");
            }}
          >
            Please Login
          </button>
        </div>
      ) : (
        <div>
          {product.length === 0 ? (
            <figure className="figure">
              <img
                src={cartImage}
                alt="cart"
                style={{ width: "100px", height: "100px" }}
              />
              <figcaption className="figure-caption text-xs-right">
                No Product Added
              </figcaption>
            </figure>
          ) : (
            <div className="d-flex">
              {product.map((item) => {
                return (
                  <div className="card">
                    <img
                      src={new Buffer.from(item.pimg).toString("ascii")}
                      className="img-fluid crd-img"
                    />
                    <div className="card-body">
                      <h5 className="card-title">{item.pname}</h5>
                      <p className="card-text">{item.pprice}</p>
                      <button
                        className="btn btn-primary"
                        onClick={() => removeFromCart(item)}
                      >
                        Remove
                      </button>
                    </div>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      )}
    </div>
  );
};

export default Cart;

so I made the removeFromCart function as useEffect dependency so it works fine but its calls the backend again and again.

 const removeFromCart = (item) => {
    Axios.delete(`http://localhost:3002/cart/${item.Id}`).then((res) => {
      setProduct(
        product.filter((item) => {
          return item.Id !== res.data.Id;
        })
      );
    });
  };

  useEffect(() => {
    Axios.get(`http://localhost:3002/cart/${user.Id}`).then((res) => {
      setProduct(res.data);
    });
  }, [user,removeFromCart]);

Is there any other way to re render useEffect

CodePudding user response:

Put axios.get in a function.

const getProduct = useCallback(() => {
    Axios.get(`http://localhost:3002/cart/${user.Id}`).then((res) => {
        setProduct(res.data);
    });
}, [user]);

const removeFromCart = (item) => {
    Axios.delete(`http://localhost:3002/cart/${item.Id}`).then((res) => {
        getProduct();
    });
};

useEffect(() => {
    getProduct();
}, [getProduct]);

CodePudding user response:

What you need is not useEffect. Use a 'state' to store the items and add or delete items using setState when 'state' gets updated react will automatically re-render. And you can use the updated state to save in your database. Also update state before calling axios

CodePudding user response:

You can add a boolean state like this :

const [isClicked, setIsCliked] = useState(false);

And toogle the boolean value whenever the button is clicked

 const removeFromCart = (item) => {
    Axios.delete(`http://localhost:3002/cart/${item.Id}`).then((res) => {
      setProduct(
        product.filter((item) => {
          return item.Id !== res.data.Id;
        })
      );
      setIsCliked(bool => !bool)
    });
  };

And your useEffect may now look like this :

      useEffect(() => {
    Axios.get(`http://localhost:3002/cart/${user.Id}`).then((res) => {
      setProduct(res.data);
    });
  }, [user.id,isClicked]);

There must be a better way but this should work

  • Related