简体   繁体   中英

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);

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

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM