我在useEffect
称为的自定义钩子内useCustomHook
使用,useCustomHook
在两个组件(即(First,Second))中使用了它,但是useEffect
仅在First
和Second
组件被渲染时才被调用。
例如
我有一个第一部分
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>)
}
这是我的customHook
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])
}
我的主要App组件
import First from './first'
import Second from './second'
function App(){
return (
<div>
<First/>
<Second/>
</div>
)
}
我的控制台输出是:
1)组件先渲染
2)useCustomHook被调用
3)组件二次渲染
4)useCustomHook被调用
5)(2)调用useEffect
我想知道
为什么行5
输出不在行之后2
,为什么Second
组件日志在line之后发生2
,因为useEffect
应该useCustomHook
在First
组件被调用之后但在该Second
组件日志被调用之前调用。为什么useEffect
内部useCustomHook
没有在Second
组件日志之前被调用。
您的输出是应该的。
我认为您对输出感到困惑,因为您认为这与输出useEffect
相同componentDidMount
但不正确。它们两者都是不同的,它们之间的几个重要区别如下:
(与您的问题有关)
它们都在组件的初始渲染之后被调用,但是在浏览器绘制屏幕之后useEffect
被调用,而在浏览器绘制屏幕之前componentDidMount
被调用。
(与您的问题无关,请随时跳到答案的结尾)
useEffect
捕获状态和道具,componentDidMount
但不这样做。
考虑以下代码片段,以了解useEffect捕获状态和道具的含义。
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>
这两个代码段是相同的,除了第一个具有基于类的组件,第二个具有功能性组件。
这两个片段都有一个count
状态为的count
变量,并且都在4秒钟后将变量的值记录到控制台。它们还包括一个按钮,可用于增加的值count
。
尝试count
在控制台上记录的值之前单击按钮(4或5次)。
如果您认为componentDidMount
和useEffect
相同,那么你可能会惊讶地看到,无论是代码片段记录的不同值count
4秒钟后变量。
基于类的代码段记录最新值,而基于功能组件的代码段记录count
变量的初始值。
他们记录count
变量的不同值的原因是:
this.state
内部类组件始终指向最新状态,因此它将记录count
4秒后的最新值。
useEffect
捕获count
变量的初始值并记录捕获的值,而不是最新值。
要深入了解useEffect
和之间的区别componentDidMount
,建议您阅读以下文章
如果您关注我的回答是关系到你的问题的第一部分,你可能现在明白为什么useEffect
两个后运行其回调First
和Second
组件已经安装。
如果没有,那么让我解释一下。
在执行useCustomHook
从First
组件内部调用的函数之后,First
将挂载组件,如果它是基于类的组件,则此时componentDidMount
将调用其生命周期函数。
在First
安装Second
组件之后,再进行组件安装,如果这也是基于类的组件,则此时componentDidMount
将调用其生命周期功能。
在安装了两个组件之后,浏览器会绘制屏幕,结果,您会在屏幕上看到输出。浏览器绘制完屏幕后,useEffect的回调函数将同时针对First
和Second
组件执行。
简而言之,useEffect
让浏览器在运行效果/回调之前先绘制屏幕。这就是useEffect gets called
在输出末尾记录日志的原因。
您可以在官方文档中查看有关此内容的更多详细信息:效果时序
如果您打开First
并Second
在对类组件的组件,然后输出应该是:
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
每个组件的执行。
如果创建Third
和Fourth
组件并创建以下类组件层次结构:
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
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句