1

作为 React 的新手,重新渲染组件似乎是不应该做的事情。因此,例如,如果我想创建一个遵循此架构的菜单 : Appis parent of Menu,它具有map创建MenuItem组件的功能

  • 菜单项来自数据源(这里是const data
  • 当我单击 a 时MenuItem,它会使用所选MenuItem值更新状态

现在很好,除了所有组件都被重新渲染(见于各种console.log

这是代码:

应用程序

import React, { useState} from "react"
import Menu from "./menu";

function App() {

  const data = ["MenuItem1", "MenuItem2", "MenuItem3", "MenuItem4", "MenuItem5", "MenuItem6"]

  const [selectedItem, setMenuItem] = useState(null)

  const handleMenuItem = (menuItem) => {
    setMenuItem(menuItem)
  }

  return (
    <div className="App">
      <Menu items = {data} handleMenuItem = {handleMenuItem}></Menu>
      <div>{selectedItem}</div>
    </div>
  );
}

export default App;

菜单

import React from "react";
import MenuItem from "./menuItem";

const Menu = (props) => {

    return (
        <>
            {props.items.map((item, index) => {
                return <MenuItem key = {index} handleMenuItem = {props.handleMenuItem} value = {item}></MenuItem>
            })
            }
            {console.log("menuItem")}
        </>
    )
};

export default React.memo(Menu);

菜单项

import React from "react";

const MenuItem = (props) => {

    return (
        <>
        <div onClick={() => props.handleMenuItem(props.value)}>
            <p>{props.value}</p>
        </div>
        {console.log("render du MenuItem")}
        </>
    )

};

export default React.memo(MenuItem);

如您所见,我React.memo最后使用了,MenuItem但它不起作用,以及PureComponent

如果有人有想法,最好有一些建议。

祝你有美好的一天

4

2 回答 2

3

使用useCallback包装您的handleMenuItem函数,以避免在函数更改时重新呈现。这将创建一个将在as 道具中使用的函数引用,并且将避免重新读取,因为它始终是相同的函数实例。MenuItem

在这种情况下,我使用了一个空的依赖数组,这对您的用例是正确的。如果您的函数有任何状态引用,则应将它们添加到数组中。

  const handleMenuItem = useCallback((menuItem) => {
    setMenuItem(menuItem);
  }, []);

编辑轻松骑行1iigv4

于 2022-02-18T14:09:57.480 回答
1

这里有很多东西要解压,所以让我们开始吧。

钩子旨在防止不必要地重新渲染组件的方式是确保您使用任何未更改变量的相同实例,尤其是对象、函数和数组。我这么说是因为字符串、数字和布尔相等很容易 'abc' === 'abc'解析为真,但[] === []会是假的,因为它们是两个不同的空数组被比较,并且 JS 中对象、函数和数组的相等仅在两侧为真时才返回比较的是完全相同的项目。

也就是说,react 提供了缓存值的方法,并且仅在需要更新它们(因为它们的依赖关系发生变化)时才更新它们(通过创建新实例)。让我们从你的 app.js 开始

import React, {useState, useCallback} from "react"
import Menu from "./menu";

// move this out of the function so that a new copy isn't created every time
// the App component re-renders

const data = ["MenuItem1", "MenuItem2", "MenuItem3", "MenuItem4", "MenuItem5", "MenuItem6"]

function App() {

  const [selectedItem, setMenuItem] = useState(null);

  // cache this with useCallback.  The second parameter (the dependency
  // array) is an empty array because there are no items that, should they
  // change, we should create a new copy.  That is to say we should never
  // need to make a new copy because we have no dependencies that could
  // change.  This will now be the same instance of the same function each 
  // re-render.
  const handleMenuItem = useCallback((menuItem) => setMenuItem(menuItem), []);

  return (
    <div className="App">
      <Menu items={data} handleMenuItem={handleMenuItem}></Menu>
      <div>{selectedItem}</div>
    </div>
  );
}

export default App;

以前,每次重新渲染 App 组件时,handleMenuItem 都会设置为该函数的新副本,并且每次重新渲染data时也会设置为新数组(具有相同的条目)。这将导致每次重新渲染 App 时重新渲染子组件(菜单)。我们不希望那样。我们只希望子组件在绝对必要时重新渲染。

接下来是菜单组件。这里几乎没有任何变化,尽管我敦促您不要=在 JSX 中放置空格(key={index}而不是key = {index}.

import React from "react";
import MenuItem from "./menuItem";

const Menu = (props) => {

    return (
        <>
            {props.items.map((item, index) => {
                return <MenuItem key={index} handleMenuItem={props.handleMenuItem} value={item}/>
            })
            }
            {console.log("menuItem")}
        </>
    )
};

export default React.memo(Menu);

对于 MenuItem,让我们缓存该单击处理程序。

import React from "react";

const MenuItem = (props) => {
  // cache this function
  const handleClick = useCallback(() => props.handleMenuItem(props.value), [props.value]);

    return (
        <>
        <div onClick={handleClick}>
            <p>{props.value}</p>
        </div>
        {console.log("render du MenuItem")}
        </>
    )

};

export default React.memo(MenuItem);
于 2022-02-18T14:09:16.087 回答