Diretório de artigos
Análise detalhada de useEffect
useEffecf uso básico
O livro continua com o anterior. No artigo anterior, explicamos o State Hook. Podemos usar este hook para definir o estado em componentes funcionais.
Sabemos que pode haver funções de ciclo de vida em componentes de classe, então como definir funções semelhantes ao ciclo de vida em componentes de função?
O Effect Hook permite que você conclua algumas funções semelhantes ao ciclo de vida em sala de aula;
De fato, semelhante às solicitações de rede, atualização manual do DOM e monitoramento de alguns eventos são alguns efeitos colaterais (efeitos colaterais) da atualização do DOM pelo React;
Assim, o Gancho que completa essas funções é chamado de Gancho de Efeito;
Suponha que agora tenhamos um requisito: o título na página sempre exibe o número do contador, que é implementado usando componentes de classe e Hook, respectivamente :
Implementação do componente de classe
import React, {
PureComponent } from 'react'
export class App extends PureComponent {
constructor() {
super()
this.state = {
counter: 100
}
}
// 进入页面时, 标题显示counter
componentDidMount() {
document.title = this.state.counter
}
// 数据发生变化时, 让标题一起变化
componentDidUpdate() {
document.title = this.state.counter
}
render() {
const {
counter } = this.state
return (
<div>
<h2>{
counter}</h2>
<button onClick={
() => this.setState({
counter: counter+1})}>+1</button>
</div>
)
}
}
export default App
Implementação do componente de função mais Hook:
- Por meio do gancho useEffect, você pode dizer ao React que precisa executar determinadas operações após a renderização;
- useEffect exige que passemos uma função callback, que será chamada de volta depois que o React terminar de atualizar o DOM ( ou seja, depois que o componente for renderizado );
默认情况下
, seja após a primeira renderização ou após cada atualização, esta função de retorno de chamada será executada; em geral, escrevemos efeitos colaterais nesta função de retorno de chamada (como solicitações de rede, operações DOM, monitoramento de eventos )Portanto, deve-se notar que existem muitos ditados de que useEffect é usado para simular o ciclo de vida, mas não é; useEffect pode simular o ciclo de vida, mas sua principal função é realizar efeitos colaterais
import React, {
memo, useEffect, useState } from 'react'
const App = memo(() => {
const [counter, setCounter] = useState(200)
// useEffect传入一个回调函数, 在页面渲染完成后自动执行
useEffect(() => {
// 一般在该回调函数在编写副作用的代码(网络请求, 操作DOM, 事件监听)
document.title = counter
})
return (
<div>
<h2>{
counter}</h2>
<button onClick={
() => setCounter(counter+1)}>+1</button>
</div>
)
})
export default App
Efeitos colaterais claros (Efeito)
No processo de escrever componentes de classe, alguns códigos de efeitos colaterais precisam ser limpos em componentWillUnmount :
Por exemplo, chame manualmente a assinatura em nosso barramento de evento anterior ou Redux;
Todos precisam ter um cancelamento de inscrição correspondente em componentWillUnmount;
Como o Effect Hook simula o componenteWillUnmount?
O useEffect passado em 回调函数A
si pode ter um valor de retorno, que é outro回调函数B
:
type EffectCallback = () => (void | (() => void | undefined));
Por que retornar uma função em vigor?
Este é um mecanismo de limpeza opcional para efeitos. Cada efeito pode retornar uma função de limpeza;
Então você pode
添加和移除
juntar a lógica da assinatura;Todos eles fazem parte do efeito;
Quando o React limpa o efeito?
O React fará uma operação de limpeza quando o componente for atualizado e desinstalado, cancelando o último monitoramento, deixando apenas o monitoramento atual;
Conforme aprendido anteriormente, os efeitos são executados em cada renderização;
import React, {
memo, useEffect } from 'react'
const App = memo(() => {
useEffect(() => {
// 监听store数据发生改变
const unsubscribe = store.subscribe(() => {
})
// 返回值是一个回调函数, 该回调函数在组件重新渲染或者要卸载时执行
return () => {
// 取消监听操作
unsubscribe()
}
})
return (
<div>
<h2>App</h2>
</div>
)
})
export default App
Usando múltiplos useEffects
Um dos propósitos de usar o Hook é resolver o problema de que o ciclo de vida de uma classe geralmente reúne muita lógica :
Por exemplo, solicitações de rede, monitoramento de eventos e modificação manual de DOM geralmente são colocados em componentDidMount;
Vários Hooks de efeito podem ser usados em um componente de função e podemos separar a lógica em diferentes useEffects :
import React, {
memo, useEffect } from 'react'
const App = memo(() => {
// 监听的useEffect
useEffect(() => {
console.log("监听的代码逻辑")
return () => {
console.log("取消的监听代码逻辑")
}
})
// 发送网络请求的useEffect
useEffect(() => {
console.log("网络请求的代码逻辑")
})
// 操作DOM的useEffect
useEffect(() => {
console.log("操作DOM的代码逻辑")
})
return (
<div>
App
</div>
)
})
export default App
O Hook nos permite separá-los de acordo com a finalidade do código, em vez de juntar muita lógica como uma função de ciclo de vida :
依次调用
React seguirá cada efeito no componente na ordem da declaração de efeito ;
otimização de desempenho useEffect
Por padrão, a função callback de useEffect será reexecutada toda vez que for renderizada, mas isso causará dois problemas :
Alguns códigos que queremos executar apenas uma vez ( como requisições de rede, executar uma vez na primeira renderização de componentes, não precisa executar várias vezes ), semelhante ao que é feito em componentDidMount e componentWillUnmount na classe components;
Além disso, várias execuções também causarão certos problemas de desempenho;
Como decidimos quando useEffect deve ser executado e quando não deve ser executado?
useEffect na verdade tem dois parâmetros:
- Parâmetro 1: A função callback a ser executada, já utilizamos este parâmetro e não diremos mais;
- Parâmetro 2: É um tipo array, o que significa que o useEffect será reexecutado quando o estado mudar; ( quem será afetado por quem será reexecutado )
Exercícios de caso :
Efeito afetado pela contagem;
import React, {
memo, useEffect, useState } from 'react'
const App = memo(() => {
const [counter, setCounter] = useState(100)
// 发送网络请求的useEffect, 只有在counter发生改变时才会重新执行
useEffect(() => {
console.log("网络请求的代码逻辑")
}, [counter])
return (
<div>
<h2 onClick={
() => setCounter(counter+1)}>{
counter}</h2>
</div>
)
})
export default App
No entanto, se for uma função, 不希望依赖任何的内容时
também podemos passar em uma matriz vazia [] :
Então, as duas funções de callback aqui correspondem às funções de ciclo de vida componentDidMount e componentWillUnmount, respectivamente;
import React, {
memo, useEffect, useState } from 'react'
const App = memo(() => {
const [counter, setCounter] = useState(100)
// 传入空数组表示不受任何数据依赖
useEffect(() => {
// 此时传入的参数一这个回调函数: 相当于componentDidMount
console.log("监听的代码逻辑")
// 参数一这个回调函数的返回值: 相当于componentWillUnmount
return () => {
console.log("取消的监听代码逻辑")
}
}, [])
return (
<div>
<h2 onClick={
() => setCounter(counter+1)}>{
counter}</h2>
</div>
)
})
export default App
Resumo: useEffect pode simular o ciclo de vida do componente de classe anterior ( semelhante, mas não igual ) e é mais poderoso que o ciclo de vida original, azul é melhor que azul