使用在 React 中未正确调用自定义钩子内部的效果

我正在使用一个名为的自定义钩子,我在两个组件(第一,第二)中使用它,但仅在和组件得到渲染时才被调用。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


慕姐8265434
浏览 83回答 2
2回答

暮色呼如

您的输出是应该的。我认为你对输出感到困惑,因为你认为这与输出相同,但这是不正确的。它们都是不同的,它们之间的几个重要区别如下:useEffectcomponentDidMount它们在不同的时间运行(与您的问题相关)它们都是在组件的初始呈现之后调用的,但在浏览器绘制屏幕之后调用,而在浏览器绘制屏幕之前调用。useEffectcomponentDidMount捕捉道具和状态(与您的问题无关,请随时跳到答案的末尾)useEffect捕获状态和道具,而不这样做。componentDidMount请考虑以下代码片段,以了解使用效果捕获状态和道具的含义。class App extends React.Component {&nbsp; constructor() {&nbsp; &nbsp; super();&nbsp; &nbsp; this.state = {&nbsp; &nbsp; &nbsp; count: 0&nbsp; &nbsp; };&nbsp; }&nbsp; componentDidMount() {&nbsp; &nbsp; setTimeout(() => {&nbsp; &nbsp; &nbsp; console.log('count value = ' + this.state.count);&nbsp; &nbsp; }, 4000);&nbsp; }&nbsp; render() {&nbsp; &nbsp; return (&nbsp; &nbsp; &nbsp; <div>&nbsp; &nbsp; &nbsp; &nbsp; <p>You clicked the button { this.state.count } times</p>&nbsp; &nbsp; &nbsp; &nbsp; <button&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; onClick={ () => this.setState(prev => ({ count: prev.count + 1 })) }>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Increment Counter&nbsp; &nbsp; &nbsp; &nbsp; </button>&nbsp; &nbsp; &nbsp; </div>&nbsp; &nbsp; );&nbsp; }}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() {&nbsp; const [count, setCount] = React.useState(0);&nbsp; React.useEffect(() => {&nbsp; &nbsp; setTimeout(() => {&nbsp; &nbsp; &nbsp; console.log('count value = ' + count);&nbsp; &nbsp; }, 4000);&nbsp; }, [])&nbsp;&nbsp;&nbsp; return (&nbsp; &nbsp; <div>&nbsp; &nbsp; &nbsp; <p>You clicked the button { count } times</p>&nbsp; &nbsp; &nbsp; <button&nbsp; &nbsp; &nbsp; &nbsp; onClick={ () => setCount(count + 1) }>&nbsp; &nbsp; &nbsp; &nbsp; Increment Counter&nbsp; &nbsp; &nbsp; </button>&nbsp; &nbsp; </div>&nbsp; );}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它们记录变量的不同值的原因是:countthis.state类内部组件始终指向最新状态,因此它会记录 4 秒后的最新值。countuseEffect&nbsp;捕获变量的初始值,并记录捕获的值而不是最新值。count有关 和 之间的差异的深入说明,我建议您阅读以下文章useEffectcomponentDidMountuseEffect(fn, []) 不是新的组件DidMount()完整的使用指南效果回到你的问题如果您注意了我的答案中与您的问题相关的第一部分,那么您现在可能明白了为什么在安装和组件后运行其回调。useEffectFirstSecond如果没有,那么让我解释一下。在执行从组件内部调用的函数后,将挂载组件,如果它是基于类的组件,则此时将调用其生命周期函数。useCustomHookFirstFirstcomponentDidMount在组件挂载后,组件挂载,如果这也是一个基于类的组件,则此时将调用其生命周期函数。FirstSecondcomponentDidMount安装完两个组件后,浏览器将绘制屏幕,因此,您会在屏幕上看到输出。浏览器绘制完屏幕后,将对和组件执行 useEffect 的回调函数。FirstSecond简而言之,让浏览器在运行其效果/回调之前绘制屏幕。这就是为什么记录在输出的末尾。useEffectuseEffect gets called您可以在官方文档上查看有关此内容的更多详细信息:效果时间如果将 和 组件转换为类组件,则输出将如下所示:FirstSecond1. component First rendering2. component Second rendering3. component First mounted.&nbsp; &nbsp; &nbsp; // console.log statement inside componentDidMount4. component Second mounted.&nbsp; &nbsp; &nbsp;// console.log statement inside componentDidMount您可能希望第 3 行位于第 2 位,第 2 行位于第 3 位,但事实并非如此,因为 react 首先执行所有子组件的渲染函数,然后再将它们插入 DOM 中,并且只有在它们插入到 DOM 中之后,每个组件才会执行。componentDidMount如果创建 和 组件并创建类组件的以下层次结构:ThirdFourthApp&nbsp;|__ First&nbsp;|&nbsp; &nbsp; &nbsp;|__ Third&nbsp;|&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |__ Fourth&nbsp;|&nbsp;&nbsp;|__ Second然后,您将获得以下输出:1.&nbsp; First component constructor2.&nbsp; component First rendering3.&nbsp; Third component constructor4.&nbsp; component Third rendering5.&nbsp; Fourth component constructor6.&nbsp; component Fourth rendering7.&nbsp; Second component constructor8.&nbsp; component Second rendering9.&nbsp; component Fourth mounted10. component Third mounted11. component First mounted12. component Second mounted

倚天杖

你提到的顺序完全有道理,这就是钩子的工作原理。流:First组件开始执行。在组件中,在代码行之后,将执行FirstuseCustomHook(count)useCustomHook在控制台中.log,并执行 useEffect,并且使用效果采取的回调为“已注册”和“未执行”。useCustomHookFirst组件返回 JSX。即组件被安装/渲染。一旦组件被挂载,就会调用使用效果的回调。FirstuseCustomHook基本上,组件内部的范围限定为组件。useCustomHookFirst第二组件也是如此...
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript