简体   繁体   English

React Re-Render 问题:如何停止重新渲染?

[英]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.问题是我有一个包含 4 个不同组件的布局组件。 When i call a function in a function component it affects the others and the others re-render.当我在 function 组件中调用 function 时,它会影响其他组件并且其他组件会重新渲染。 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这是我的 App 组件

 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. React 开箱即用的速度非常快——它应该在 props 不改变时重新渲染组件。 But, just to illustrate, you can design your components (using children ) so that not everything re-renders all the time.但是,为了说明,您可以设计您的组件(使用children ),这样就不会一直重新渲染所有内容。

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.您可以使用React.memo ,但是记忆一个组件很容易最终成为性能损失,而不是胜利。 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.如果您在布局组件中设置新的 state,它将重新运行并重新渲染其 JSX 中的所有组件。
Don't worry, it is not the problem of React.别担心,这不是 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).如果您希望您的HeaderMenuCartFooter不被重新渲染,请阅读 React.PureComponent(用于类)、React.memo 或 useMemo、useCallback(用于功能组件)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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