- 副作用:渲染以外的操作:像后端获取数据、操作DOM
- 参数:副作用方法、依赖(改变时重新执行)
- 调用时间:渲染JSX之后/依赖改变
useEffect
是 React 中的一个 Hook,用于在函数组件中执行副作用操作。副作用操作包括数据获取、订阅或手动更改 React 组件中的 DOM 等。useEffect
使得在函数组件中处理这些操作变得简单而强大。
基本用法
useEffect
接受一个函数和一个依赖数组作为参数。当依赖数组中的任何值发生变化时,该函数将被重新执行。如果没有提供依赖数组,则该函数将在每次渲染后执行。
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
// 副作用操作
document.title = `You clicked ${count} times`;
// 清理函数(可选)
return () => {
// 组件卸载或依赖项变化前执行的清理操作
console.log('Clean up');
};
}, [count]); // 只有当 count 变化时,副作用操作才会重新执行
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
详解
- 副作用函数:
useEffect
第一个参数是一个函数,该函数中包含了所有副作用操作。- 这些操作可以是数据获取、订阅外部数据源、手动操作 DOM 等。
- 依赖数组:
- 第二个参数是一个依赖数组(依赖项)。
- 当数组中的某个依赖项发生变化时,副作用函数会重新执行。
- 如果省略这个数组,副作用函数会在每次渲染后执行。
- 清理函数:
- 副作用函数可以返回一个函数,这个函数会在组件卸载或下次副作用执行前执行。
- 常用于取消订阅、清除计时器、还原之前的手动 DOM 操作等。
- 空依赖数组:
- 如果依赖数组为空
[]
,则副作用函数只会在组件挂载和卸载时执行一次。 - 这类似于类组件中的
componentDidMount
和componentWillUnmount
。
- 如果依赖数组为空
- 多个
useEffect
:- 你可以在一个组件中使用多个
useEffect
来分离不同的副作用逻辑。 - 每个
useEffect
都可以有自己的依赖数组和清理函数。
- 你可以在一个组件中使用多个
注意事项
- 避免在副作用函数中直接修改状态:
- 副作用函数应该只包含副作用操作,如数据获取、订阅等。
- 状态更新应该通过事件处理函数或其他 React 机制来进行。
- 确保清理函数无副作用:
- 清理函数中的操作应该是幂等的,即多次执行相同操作不会改变状态或导致错误。
- 依赖项要准确:
- 确保依赖数组包含所有影响副作用函数行为的变量,以避免不必要的副作用执行。
示例
以下是一个包含多个 useEffect
的示例,分别处理数据获取和手动 DOM 操作:
import React, { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [input, setInput] = useState('');
useEffect(() => {
// 数据获取副作用
fetch(`https://api.example.com/data?query=${input}`)
.then(response => response.json())
.then(result => setData(result))
.catch(error => console.error('Error fetching data:', error));
}, [input]); // 仅在 input 变化时重新获取数据
useEffect(() => {
// 手动 DOM 操作副作用
const element = document.getElementById('focusElement');
if (element) {
element.focus();
}
// 清理函数
return () => {
if (element) {
element.blur();
}
};
}, []); // 只在组件挂载和卸载时执行
return (
<div>
<input
type="text"
value={input}
onChange={e => setInput(e.target.value)}
placeholder="Search..."
/>
{data ? (
<div>
<h1>{data.title}</h1>
<p>{data.description}</p>
<input id="focusElement" type="text" placeholder="Auto-focused" />
</div>
) : (
<p>Loading...</p>
)}
</div>
);
}
useEffect
是 React 函数组件中的一个 Hook,用于执行副作用操作。副作用操作是那些不在 React 渲染过程中的操作,比如数据获取、订阅外部数据源、手动更改 DOM 等。useEffect
使得在函数组件中处理这些操作变得简单而强大。
useEffect 的基本用法
useEffect
接受一个函数(副作用函数)和一个依赖数组作为参数。当依赖数组中的任何值发生变化时,副作用函数会重新执行。如果省略依赖数组,副作用函数会在每次组件渲染后都执行。
useEffect(() => {
// 副作用操作
return () => {
// 清理操作(可选)
};
}, [dependency1, dependency2, ...]); // 依赖数组
依赖数组
依赖数组是 useEffect
的第二个参数,它是一个包含依赖项的数组。这些依赖项通常是组件的状态变量或 props。当数组中的任何一个依赖项发生变化时,React 会重新调用 useEffect
中的副作用函数。
- 如果依赖数组为空(
[]
),则副作用函数只会在组件挂载(componentDidMount
等效)和卸载(componentWillUnmount
等效)时执行一次。 - 如果依赖数组包含状态变量或 props,则每当这些依赖项变化时,副作用函数会重新执行。
注意事项
- 副作用函数内部不应该直接修改状态或触发其他副作用,因为这可能会导致无限循环或其他难以调试的问题。状态更新应该通过事件处理函数或其他 React 机制来进行。
- 清理函数(
useEffect
返回的函数)用于在副作用函数执行完毕后进行清理操作,比如取消订阅、清除计时器等。它会在组件卸载或下次副作用执行前执行。 - 依赖数组应该包含所有影响副作用函数行为的变量,以避免不必要的副作用执行。
示例
以下是一个使用 useEffect
和依赖数组的示例,用于在组件挂载时获取数据,并在数据变化时更新 UI
import React, { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [query, setQuery] = useState('');
useEffect(() => {
// 数据获取副作用
fetch(`https://api.example.com/data?query=${query}`)
.then(response => response.json())
.then(result => setData(result))
.catch(error => console.error('Error fetching data:', error));
}, [query]); // 依赖数组包含 query,当 query 变化时重新获取数据
return (
<div>
<input
type="text"
value={query}
onChange={e => setQuery(e.target.value)}
placeholder="Search..."
/>
{data ? (
<div>
<h1>{data.title}</h1>
<p>{data.description}</p>
</div>
) : (
<p>Loading...</p>
)}
</div>
);
}