亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用在 React 中未正確調用自定義鉤子內部的效果

使用在 React 中未正確調用自定義鉤子內部的效果

慕姐8265434 2022-09-29 15:28:16
我正在使用一個名為的自定義鉤子,我在兩個組件(第一,第二)中使用它,但僅在和組件得到渲染時才被調用。useEffectuseCustomHookuseCustomHookuseEffectFirstSecond例如我有第一個組件import React,{useState} from 'react'import useCustomHook from './customHook'function First(){ console.log("component First rendering") const [count,setCount]=useState(0) useCustomHook(count) return (<div>First component</div>)}這是我的第二個組成部分import React,{useState} from 'react'import useCustomHook from './customHook'function Second(){ console.log("component Second rendering") const [count,setCount]=useState(0) useCustomHook(count) return (<div>Second component</div>)}這是我的自定義鉤子import {useEffect} from 'react'function useCustomHook(count){  console.log("useCustomHook getting called")  useEffect(()=>{ console.log("useEffect gets called") //this function is running after both component rendered  },[count])}我的主要應用組件import First from './first'import Second from './second'function App(){   return (      <div>        <First/>        <Second/>      </div>    )}我的控制臺輸出是 :1) 組件首次渲染2)使用被調用的自定義鉤子3) 組件 二次渲染4)使用被調用的自定義鉤子5) (2) 使用效果被調用我想知道為什么是行輸出不是在行之后,為什么組件日志發生在行之后,因為應該在被組件調用之后但在調用組件日志之前調用。為什么在組件日志之前沒有被調用。52Second2useEffectuseCustomHookFirstSeconduseEffectuseCustomHookSecond
查看完整描述

2 回答

?
暮色呼如

TA貢獻1853條經驗 獲得超9個贊

您的輸出是應該的。

我認為你對輸出感到困惑,因為你認為這與輸出相同,但這是不正確的。它們都是不同的,它們之間的幾個重要區別如下:useEffectcomponentDidMount

它們在不同的時間運行

(與您的問題相關)

它們都是在組件的初始呈現之后調用的,但在瀏覽器繪制屏幕之后調用,而在瀏覽器繪制屏幕之前調用。useEffectcomponentDidMount

捕捉道具和狀態

(與您的問題無關,請隨時跳到答案的末尾)

useEffect捕獲狀態和道具,而不這樣做。componentDidMount

請考慮以下代碼片段,以了解使用效果捕獲狀態和道具的含義。

class App extends React.Component {

  constructor() {

    super();

    this.state = {

      count: 0

    };

  }


  componentDidMount() {

    setTimeout(() => {

      console.log('count value = ' + this.state.count);

    }, 4000);

  }


  render() {

    return (

      <div>

        <p>You clicked the button { this.state.count } times</p>

        <button

          onClick={ () => this.setState(prev => ({ count: prev.count + 1 })) }>

          Increment Counter

        </button>

      </div>

    );

  }

}


ReactDOM.render(<App />, document.getElementById('root'));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>


<div id="root"></div>

function App() {

  const [count, setCount] = React.useState(0);


  React.useEffect(() => {

    setTimeout(() => {

      console.log('count value = ' + count);

    }, 4000);

  }, [])

  

  return (

    <div>

      <p>You clicked the button { count } times</p>

      <button

        onClick={ () => setCount(count + 1) }>

        Increment Counter

      </button>

    </div>

  );

}


ReactDOM.render(<App />, document.getElementById('root'));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>


<div id="root"></div>

兩個代碼片段是相同的,除了第一個代碼片段具有基于類的組件,第二個代碼片段具有功能組件。

這兩個代碼段都有一個名為 狀態的變量,它們都在 4 秒后將變量的值記錄到控制臺。它們還包括一個按鈕,可用于遞增 .countcountcount

嘗試單擊按鈕(4 或 5 次),然后將 的值記錄在控制臺上。count

如果您認為這一點并且相同,那么您可能會驚訝地發現兩個代碼片段在4秒后都記錄了不同的變量值。componentDidMountuseEffectcount

基于類的代碼段記錄最新值,而基于函數組件的代碼段記錄變量的初始值。count

它們記錄變量的不同值的原因是:count

  • this.state類內部組件始終指向最新狀態,因此它會記錄 4 秒后的最新值。count

  • useEffect 捕獲變量的初始值,并記錄捕獲的值而不是最新值。count

有關 和 之間的差異的深入說明,我建議您閱讀以下文章useEffectcomponentDidMount


回到你的問題

如果您注意了我的答案中與您的問題相關的第一部分,那么您現在可能明白了為什么在安裝和組件后運行其回調。useEffectFirstSecond

如果沒有,那么讓我解釋一下。

在執行從組件內部調用的函數后,將掛載組件,如果它是基于類的組件,則此時將調用其生命周期函數。useCustomHookFirstFirstcomponentDidMount

在組件掛載后,組件掛載,如果這也是一個基于類的組件,則此時將調用其生命周期函數。FirstSecondcomponentDidMount

安裝完兩個組件后,瀏覽器將繪制屏幕,因此,您會在屏幕上看到輸出。瀏覽器繪制完屏幕后,將對和組件執行 useEffect 的回調函數。FirstSecond

簡而言之,讓瀏覽器在運行其效果/回調之前繪制屏幕。這就是為什么記錄在輸出的末尾。useEffectuseEffect gets called

您可以在官方文檔上查看有關此內容的更多詳細信息:效果時間

如果將 和 組件轉換為類組件,則輸出將如下所示:FirstSecond

1. component First rendering

2. component Second rendering

3. component First mounted.      // console.log statement inside componentDidMount

4. component Second mounted.     // console.log statement inside componentDidMount

您可能希望第 3 行位于第 2 位,第 2 行位于第 3 位,但事實并非如此,因為 react 首先執行所有子組件的渲染函數,然后再將它們插入 DOM 中,并且只有在它們插入到 DOM 中之后,每個組件才會執行。componentDidMount


如果創建 和 組件并創建類組件的以下層次結構:ThirdFourth


App

 |__ First

 |     |__ Third

 |          |__ Fourth

 | 

 |__ Second

然后,您將獲得以下輸出:


1.  First component constructor

2.  component First rendering

3.  Third component constructor

4.  component Third rendering

5.  Fourth component constructor

6.  component Fourth rendering

7.  Second component constructor

8.  component Second rendering

9.  component Fourth mounted

10. component Third mounted

11. component First mounted

12. component Second mounted


查看完整回答
反對 回復 2022-09-29
?
倚天杖

TA貢獻1828條經驗 獲得超3個贊

你提到的順序完全有道理,這就是鉤子的工作原理。

流:

  • First組件開始執行。

  • 在組件中,在代碼行之后,將執行FirstuseCustomHook(count)useCustomHook

  • 在控制臺中.log,并執行 useEffect,并且使用效果采取的回調為“已注冊”和“未執行”。useCustomHook

  • First組件返回 JSX。即組件被安裝/渲染。

  • 一旦組件被掛載,就會調用使用效果的回調。FirstuseCustomHook

  • 基本上,組件內部的范圍限定為組件。useCustomHookFirst

第二組件也是如此...


查看完整回答
反對 回復 2022-09-29
  • 2 回答
  • 0 關注
  • 110 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號