Mithat Ercan
Mithat Ercan

Reputation: 399

React Re-Render Issue : How Can I Stop Re-Render?

I'm new in coding and i couldn't get how to fix the issue after i googled many times. The issue is i have a layout component which contains 4 different components. When i call a function in a function component it affects the others and the others re-render. But i don't pass the new props to them. I only pass props to one component which contains click events. I hope I made myself clear , thanks in advance. So here are my code samples :

This is my layout component.

import React, { useState } from "react";
import Header from "./Header";
import MenuTitle from "./MenuTitle";
import MenuList from "./MenuList";
import Cart from "./Cart";
import Footer from "./Footer";
function Layout({
  cartData,
  menuList,
  menuTitles,
  callMenuList,
  addToCart,
  title,
  removeFromCart,
  currency,
}) {
  const [isCartOpened, setIsCartOpened] = useState("closed");

  const openCart = () => {
    if (isCartOpened == "closed") {
      setIsCartOpened("opened");
    } else {
      setIsCartOpened("closed");
    }
  };
  const closeCart = () => {
    setIsCartOpened("closed");
  };

  return (
    <div>
      <Header openCart={() => openCart()} cartData={cartData} />
      <MenuTitle
        menuTitles={menuTitles}
        callMenuList={(titleProp) => callMenuList(titleProp)}
      />
      <MenuList
        title={title}
        menuList={menuList}
        addToCart={(data) => addToCart(data)}
      />
      <Cart
        currency={currency}
        cartData={cartData}
        removeFromCart={(itemId) => removeFromCart(itemId)}
        isCartOpened={isCartOpened}
        closeCart={() => closeCart()}
      />
      <Footer />
    </div>
  );
}

export default Layout;

And this is my App component

 import React, { useState, useEffect } from "react";

import Layout from "./Components/Layout";

function App() {
  const [data, setData] = useState([]);
  const [menuTitle, setMenuTitle] = useState([]);
  const [title, setTitle] = useState("");
  const [currency, setCurrency] = useState("");
  const [menuList, setMenuList] = useState([]);
  const [cart, setCart] = useState([]);
  const API = "./db.json";

  const callMenuList = React.useCallback((titleProp) => {
    setTitle(titleProp);
    const filterMenuList = data.filter((title) => title.TYPE == titleProp);
    setMenuList(filterMenuList);
  });

  const addToCart = React.useCallback((data) => {
   
    setCart([...cart, data]);
  });

  const removeFromCart = React.useCallback((itemId) => {
    const cartItems = cart;

    cartItems.map((item) => {
      if (item.CODE == itemId) {
        const filtered = cartItems.filter(
          (cartItem) => cartItem.CODE != itemId
        );
        setCart(filtered);
      }
    });
  });

  useEffect(() => {
    const titles = [];
    const fetchData = async () => {
      const response = await fetch(API);
      const responseData = await response.json();
      setData(responseData);
      console.log(responseData);

      // Filtering menu types
      responseData.map((item) => titles.push(item.TYPE));
      const filtered = titles.filter(
        (item, index, self) => self.indexOf(item) == index
      );
      setMenuTitle(filtered);

      const initialMenuList = responseData.filter(
        (item) => item.TYPE == filtered[0]
      );

      setTitle(initialMenuList[0].TYPE);
      setCurrency(initialMenuList[0].CURRENCY);
      setMenuList(initialMenuList);
    };
      fetchData();
  }, []);

  return (
    <Layout
      menuTitles={menuTitle}
      menuList={menuList}
      data={data}
      callMenuList={(titleProp) => callMenuList(titleProp)}
      addToCart={(data) => addToCart(data)}
      removeFromCart={(itemId) => removeFromCart(itemId)}
      cartData={cart}
      title={title}
      currency={currency}
    />
  );
}

export default React.memo(App);

Upvotes: 0

Views: 4144

Answers (2)

Adam Jenkins
Adam Jenkins

Reputation: 55792

I have to add this as an answer even though it's more of a comment because so many people become overzealous about preventing renders when it doesn't matter.

React is very fast out of the box - it is supposed to be re-rendering components when props don't change. But, just to illustrate, you can design your components (using children) so that not everything re-renders all the time.

Compare these two stackblitz:

But none of this actually matters, you should only look at preventing unnecessary renders if you see performance issues.

If you see logical issues that are fixed by preventing a re-render, then you've got a bug that you need to fix somewhere else.

If you aren't experiencing any performance or logic issues, then the answer to your question is to stop worrying about it.

You can use React.memo, but memoizing a component could easily end up being a performance penalty, rather than a win. Memoizing something isn't free.

I urge you to forget about this stuff unless you are seeing performance or logical errors.

Stop worrying, everything is functioning normally when your components re-render without props/state changes if their parents have re-rendered

Upvotes: 3

dannyxnda
dannyxnda

Reputation: 1034

If you set a new state in your layout component, it will re-run and re-render all the components in its JSX.
Don't worry, it is not the problem of React. If you want your Header, Menu, Cart, Footer not to be re-render, read about React.PureComponent (for class), React.memo, or useMemo, useCallback (for funtional component).

Upvotes: 0

Related Questions