简体   繁体   English

反应 useCallback() 没有按预期工作

[英]React useCallback() not working as expected

I'm trying to understand useCallback() a bit better by creating a simple React app and playing around with it.我试图通过创建一个简单的 React 应用程序并使用它来更好地理解useCallback()

I tried wrapping handleClick function in useCallback() statement and my expectation was that ItemList component should only be re-rendered if I click the count button, but not when I change the theme.我尝试在useCallback()语句中包装handleClick函数,我的期望是ItemList组件应该只在我单击count按钮时重新渲染,而不是在我更改主题时。 However, it's rerendering on either of those button clicks and I'm not exactly sure why.但是,它会在任何一个按钮单击时重新呈现,我不确定为什么。

This is my code (GitHub repo available below):这是我的代码(下面提供 GitHub 存储库):

index.js: index.js:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import SebComponent from './SebComponent';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.Fragment>
    <App />
    <SebComponent />
  </React.Fragment>
);

App.js应用程序.js

function App() {
  return (
    <div>
      <p>This is App</p>
      {console.log("App compoent rendered")}
    </div>
  );
}

export default App;

SebComponent.js SebComponent.js

import React, { useCallback, useState } from "react";
import ItemList from "./itemList";
import "../src/sebstyle.css"

function SebComponent(){

    console.log("rendering SebComponent...")
    const [count, setCount] = useState(1)
    const [dark, setDark] = useState(false)

    let inlineStyle = {backgroundColor: dark ? "green" : "white"}

    
    const handleClick = useCallback(() => {
        setCount(count + 1)
    }, [count])


    return(
        <div className="sebComponent" style={inlineStyle}>
            <p>This is SebComponent</p>
            <button onClick={handleClick}> {count} </button>
            <br/>
            <br/>
            <button onClick={() => {setDark(x => !x)}}> change theme </button>

            <ItemList count={count}/>
        </div>
    )
}

export default SebComponent;

itemList.js: itemList.js:

import React from "react";

export default function ItemList(props){

    console.log("rendering item list...")
    let myArray = [];

    for (let index = 1; index < props.count; index++) {
        myArray.push( 'item' + index);
    }
    
    console.log(myArray);

    return(
        <div>
            <p>hello</p>

            {myArray.map(
                    x => {
                        return (
                            <p key={"item" + x}> {x} </p>
                        )
                    }
                )
            }

        </div>
    )
}

sebstyle.css: sebstyle.css:

.sebComponent{
    border: 2px black solid;
    display:block;
    align-items: center;
    padding: 5px;
}

.sebComponent > button{
    margin-left: 10px;
    width: 100px;
    height: 40px;

}

I tried creating something similar to what this guy did in his video .我尝试创建类似于这个人在他的视频中所做的事情。 This is my GitHub repo created to play around with this.这是我为解决这个问题而创建的 GitHub 存储库

If you want to skip rendering ItemList, then ItemList needs to use React.memo .如果你想跳过渲染 ItemList,那么 ItemList 需要使用React.memo This will make it so if ItemList's props have not changed, then ItemList will not rerender:这将使得如果 ItemList 的道具没有改变,那么 ItemList 将不会重新渲染:

import { memo } from 'react';

function ItemList(props){
  // ...
}

export default memo(ItemList);

The only role useCallback serves in preventing rendering is to make sure that props do not change. useCallback 在阻止渲染中的唯一作用是确保 props 不会改变。 That in turn can allow memo to do its job.这反过来又可以让备忘录发挥作用。 But handleClick is never being passed to ItemList, so nothing is happening to item list by memomizing handleClick但是handleClick永远不会被传递给ItemList,所以通过记忆handleClick不会对项目列表发生任何事情

When one of those hook is invoked ( const [count, setCount] = useState(1) const [dark, setDark] = useState(false) ) React re-render all the page.当调用其中一个钩子时( const [count, setCount] = useState(1) const [dark, setDark] = useState(false) )React 重新渲染所有页面。 You can work-around with some library as redux that let manage way more better hook.您可以使用一些库作为 redux 来解决问题,让管理方式更好。 for more info read this: How to prevent re-rendering of components that have not changed?有关更多信息,请阅读: 如何防止重新渲染未更改的组件?

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

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