浅析React Hook中useEffecfa函数的使用

1. 什么是React Hook中的useEffect函数?

在React的函数式组件中,如果我们需要实现类似于componentDidMount和componentDidUpdate的生命周期函数的效果,那么就可以使用React Hook中的useEffect函数。

useEffect的作用是:在函数组件中执行副作用操作,如获取数据,设置订阅,以及手动更改React组件中的DOM元素。

useEffect函数接受两个参数,第一个参数是一个函数,表示需要执行的副作用操作;第二个参数是一个数组,表示需要跟踪的变量列表。useEffect函数会在组件渲染完成后执行第一个参数所表示的函数(又称为effect函数),如果指定了第二个参数,则只有在数组中的变量发生了变化,才会重新执行effect函数,否则effect函数不会再次执行。

2. useEffect函数的参数详解

2.1 第一个参数

useEffect函数的第一个参数是一个函数,可以执行任何需要的操作。这个函数有两种形式:

// 第一种形式:不带返回值的函数

function useEffect(effect: EffectCallback, deps?: DependencyList): void;

// 第二种形式:带返回值的函数

function useEffect(effect: EffectCallback, deps?: DependencyList): (() => void) | void;

第一种形式的函数不需要返回值,只需要执行想要的操作,如获取数据,更新组件等。

第二种形式的函数需要带返回值,返回一个清除函数,用于清除effect的副作用。在组件卸载时,React会自动执行这个清除函数。

2.2 第二个参数

useEffect函数的第二个参数是一个数组,用于指定useEffect的依赖项。只有当数组中的依赖项发生了变化时,useEffect才会重新执行。如果不指定第二个参数,默认为[],即只在组件首次渲染时执行effect函数。

useEffect函数的第二个参数的类型为DependencyList,它是一个数组类型。数组中存放着effect函数需要依赖的变量,当这些变量的值发生变化时,effect函数才会重新执行。

需要注意的是,依赖项的内容一定要是完整的(如果是对象,则每个属性都要列举出来),否则会导致effect不执行或者effect不会预期地执行。

3. useEffect函数的常见用法

3.1 使用useEffect获取数据

在React中,我们经常需要从服务器获取数据并且显示在组件中。借助useEffect函数,我们可以在组件渲染完成后获取数据,然后再更新组件。

示例代码如下:

import React, { useState, useEffect } from 'react';

import axios from 'axios';

function App() {

const [users, setUsers] = useState([]);

useEffect(() => {

axios.get('https://jsonplaceholder.typicode.com/users')

.then(res => setUsers(res.data))

.catch(err => console.log(err));

}, []);

return (

<div>

<h1>Users:</h1>

<ul>

{users.map(user => (

<li key={user.id}>

{user.name}

</li>

))}

</ul>

</div>

);

}

export default App;

代码中,我们使用了useEffect来获取数据,并使用useState来保存数据。getAllUsers函数用于获取用户数据,这个函数会在组件渲染完成后自动执行,因为在useEffect的第二个参数中传递了一个空数组,表示只需要在组件首次渲染时执行这个函数。

3.2 使用useEffect更新DOM元素

除了获取数据之外,使用useEffect还可以用来手动更新DOM元素,这个场景在组件需要根据用户的操作来改变dom结构时尤为适用。我们可以在effect函数中,手动操作DOM元素,然后更新组件。

示例代码如下:

import React, { useState, useEffect, useRef } from 'react';

function App() {

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

const countRef = useRef();

useEffect(() => {

countRef.current.innerHTML = count;

}, [count]);

return (

<div>

<h1>Count: <span ref={countRef}></span></h1>

<button onClick={() => setCount(count + 1)}>+</button>

<button onClick={() => setCount(count - 1)}>-</button>

</div>

);

}

export default App;

代码中,我们使用了useEffect函数来手动更新DOM元素。当count变量的值发生变化时,effect函数会重新执行,然后将count的值更新到DOM元素中。

3.3 使用useEffect实现类似于componentDidMount和componentDidUpdate的效果

在React中,我们经常需要在组件挂载后执行一些操作,如设置订阅,更新DOM元素等,这个场景下,可以使用useEffect来实现类似于componentDidMount的效果。同时,还可以使用useEffect来监听组件中某个变量的变化,然后进行相关操作,这个场景下,可以使用useEffect来实现类似于componentDidUpdate的效果。

示例代码如下:

import React, { useState, useEffect } from 'react';

function App() {

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

useEffect(() => {

document.title = 'Count: ' + count;

}, [count]);

return (

<div>

<h1>Count: {count}</h1>

<button onClick={() => setCount(count + 1)}>+</button>

<button onClick={() => setCount(count - 1)}>-</button>

</div>

);

}

export default App;

代码中,我们使用了useEffect函数来监听count变量的变化。当count变量的值发生变化时,effect函数会重新执行,然后更新document.title的值。

4. useEffect函数的常见问题

在使用useEffect函数时,我们需要注意一些问题,否则可能会导致效果出现一些意外情况。

4.1 必须在函数组件的顶层使用

useEffect函数必须在函数组件的顶层使用,而不能在嵌套的函数或条件语句中使用。这是因为React需要保证每次渲染时都能执行effect函数,如果useEffect被放在了条件语句中,则可能只有在特定条件下才会执行effect函数,这样可能会导致程序出现一些异常。

4.2 useEffect的执行不保证同步

React在运行useEffect函数时,并不保证其同步执行,也就是说,useEffect函数的执行可能会先于组件渲染完成,或者在组件渲染完成之后。因此,我们在使用useEffect函数时,需要避免依赖更新后立即执行的操作,如获取DOM节点的尺寸,因为此时DOM节点可能还未被渲染完成。

4.3 清除副作用的代码应该在effect函数内部定义

在使用useEffect函数时,如果需要清理副作用操作,在代码中最好将清除副作用的代码定义在effect函数内部,这样有助于组织逻辑和避免出现一些代码错误。

5. 总结

useEffect函数是React提供的一个非常强大的工具,它可以帮助我们在函数式组件中实现componentDidMount和componentDidUpdate等生命周期函数的功能,同时在需要时可以更新DOM元素,或者获取数据。使用useEffect函数时,我们需要注意函数的参数和使用方式,避免出现一些错误情况。