簡體   English   中英

在 React 功能組件中重新渲染 - 為什么會出現這種行為?

[英]Re-rendering in React functional component - why this behavior?

這個問題涉及功能組件內部回調函數的定義,回調函數作為道具傳遞給子功能組件。 我知道在功能組件中定義函數並且這些函數作為道具傳遞給子組件時,我們應該使用useCallback 在這個例子中,我故意不使用它。

我有一個虛擬的 React 應用程序,如下所示:

應用程序.jsx

import { useState, useCallback } from 'react';
import './App.css';
import TestComponent from './components/TestComponent';
import TestComponent2 from './components/TestComponent2';

function App() {

    const [message, setMessage] = useState("");
    console.log('Defining myArrowfunc');
    const myArrowFunc = () => console.log('Hello!');
    console.log('myArrowfunc defined');

    return (
        <>
            <TestComponent message={message} myArrowFunc={myArrowFunc} />
            <TestComponent2 myArrowFunc={myArrowFunc} />
            <input
                type="text"
                value={message}
                onChange={e => setMessage(e.target.value)}
            />
            <button
                type="button"
                onClick={() => {
                    console.log('Setting message');
                    setMessage("x");
            }}>Set to x</button>
        </>
    );
}

export default App;

測試組件.jsx

import { useEffect } from 'react';

function TestComponent(props) {
    
    useEffect(() => {
        console.log(`TestComponent.useEffect, props.message = ${props.message}`);
    }, [props]);
    
    return <h2>TestComponent - {props.message}</h2>;
}

export default TestComponent;

測試組件2.jsx

import { useEffect } from 'react';

function TestComponent2(props) {
    
    useEffect(() => {
        console.log(`TestComponent2.useEffect`);
    }, [props.myArrowFunc]);
    
    return <h2>TestComponent2 - Placeholder</h2>;
}

export default TestComponent2;

啟動應用程序,頁面加載,我們在這里:

初始應用加載

在控制台窗口中,一切看起來都像預期的那樣。 定義 myArrowFuncmyArrowFunc 定義console.log語句運行,我們可以從TestComponentTestComponent2中的useEffect掛鈎看到console.log語句,它們在渲染后運行。

現在我們單擊按鈕Set to x ,它調用附加到按鈕的onClick事件的回調函數。 此回調調用setMessage("x")更新App組件的狀態並因此觸發組件的重新渲染。

在控制台窗口中,我們可以看到App功能組件運行(例如從console.log("Defining myArrowFunc) ),還可以看到子組件的useEffect掛鈎在重新渲染后運行。

在此處輸入圖像描述

現在,重新渲染的TestComponent當然是可以理解的。 消息狀態是TestComponent上的一個道具,它會導致重新渲染TestComponent 此外,在TestComponent的依賴數組中指定了props (不是props.message ),但props是每個渲染上的新對象(對嗎?),因此參考比較告訴我們props已更改,因此useEffect運行。

TestComponent2useEffect鈎子運行可以理解(對嗎?)從myArrowFuncApp的每次渲染上重新定義的事實,因此傳遞給TestComponent2的道具實際上已經改變(參考比較)。

這是我感到困惑的部分: App中的消息狀態現在持有“x”,因此對按鈕的額外點擊不會改變狀態,因此不應觸發App的重新渲染(以及任何依賴的子組件)。 當我單擊按鈕時,會發生以下輸出:

在此處輸入圖像描述

語句console.log('Defining myArrowfunc'); console.log('myArrowfunc defined'); 跑了。 這是什么意思? 組件是否重新渲染? 如果App函數運行,那么它應該定義了一個新的myArrowFunc (對嗎?),並且由於TestComponent2將其作為道具,它應該重新渲染並運行它的useEffect鈎子?

有趣的是,當我再次單擊該按鈕時,它看起來不像App運行了,輸出只是“設置消息”。

非常感謝這里到底發生了什么的大綱/解釋。

在此處輸入圖像描述

當您單擊該按鈕時,將運行帶有設置消息的控制台日志,然后帶有 setState 將重新渲染。

在接下來的點擊中,react 足夠聰明,可以看到您設置的狀態與之前相同,因此不會重新渲染

如果您更改該值並單擊該按鈕,它將重新渲染,但對於以下具有相同值的情況則不會。

綜上所述,如果沒有重新渲染,第一個 console.log 將不會運行,並且 react 和 if default memoizing 的過程會阻止它

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM