Dignity Dignity
Dignity Dignity

Reputation: 151

In React useEffect doesn't update after the value has changed from other component

I am trying to do some kind of online shop for myself and I got a problem. I want to render my shopping cart size in the NavBar component (which is on every page).

I created a Cart Items service where I put all my added items, and it also has functions to addItem, removeItem, getCart, getCartSize.

When I click on Add/Remove on specific product, I would like to do that the value on NavBar with cart size would be changing depending on the cart size (from getCartSize method). I already tried to use useEffect hook, but it does not recognize when the value of cartSize is changed, how can I do that?

This is what I have done already.

navbar.jsx:

//...
//...
import {getTotalCount} from '../../services/myCart';

export default function Navbar() {
  // ...
  const [count, setCount] = useState();  

  useEffect(() => {
    setCount(getTotalCount());
    console.log('counto useeffect');
  },[getTotalCount()]);
  //},[getTotalCount]); doesn'work also.
  //},[count]); doesn'work also.

  return (
    <>
        <header className="navbar">
                <Link className="navbar__list-item__home-icon" to="/"><span><FaHome/></span></Link>
                <Link className="navbar__list-item" to="/products">Products</Link>            
                <h2>cart size--> {count}</h2>
                <Link className="navbar__list-item__cart-img" to="shopping-cart"><span><FaShoppingCart/></span></Link>   
        </header>
    </>
  );
}

myCart.js all functions work fine and I call them when I click add/remove button in on my component in the products page.

var InTheCart = [

];
var totalCount = 0;

export function AddToCart(item) {
    // ... logic
    totalCount++;
}

export function ContainsInTheCart(id) {
    return InTheCart.findIndex(x=> x.item.id == id) != -1 ? true: false;   
}

export function RemoveFromCart(id) {
   // ... logic
        totalCount--;
}

export function getCart() {
    return InTheCart;
}

export function getTotalCount() {
    return totalCount;
}


Upvotes: 1

Views: 6368

Answers (2)

Muhammad Zeeshan
Muhammad Zeeshan

Reputation: 4748

A simple solution is to lift the state up. Create the state in your layout file from where Header and Cart can access the count as Props. useEffect will be invoked whenever there is a change in the state or props of a component.

Upvotes: 1

Pandaiolo
Pandaiolo

Reputation: 11586

React is called react because it re-renders when it reacts to something that changed.

For that to happen, the react components need to know, somehow, that something changed.

In the code example you show, the totalCount (which global access provided by exported function getTotalCount) is independent from react component tree, so that data can change without react knowing it.

So, the question is: how to make your react component aware of those changes?

A few mechanisms exist, here are a few of them:

  1. Use a global state manager like redux, with redux actions and reducer to mutate the state and useSelector in the component that will make them aware of any change, and rerender

  2. React context which will hold the cart state. That context can export both that data, and th function that will mutate the data, so they can be shared between components that have access to that context provider.

Your context could be used in the component that way:

  const cartContext = useContext(CartContext)
  const { cartState, addToCart, removeFromCart } = cartContext
  const { totalCount, inTheCart } = cartState

  [...somwhere later...]
  <ul><li onClick={() => removeFromCart(index)}>{inTheCart[index].name}</li></ul>
  <footer>{`${totalCount} items`}</footer>

I let you build the context object around your existing functions ;)

Upvotes: 1

Related Questions