文章目录
useEffect
是 React 钩子函数之一,它使函数组件能够执行副作用操作。常见的副作用包括数据获取、订阅、手动更改 React 组件中的 DOM 以及定时器等。在类组件中,我们通常在生命周期方法中执行这些操作,而在函数组件中,我们使用useEffect
来完成这些任务。本文将详细介绍useEffect
的概念、用法及其在实际开发中的应用,旨在帮助开发者全面掌握这一重要特性。
一、useEffect 概念
useEffect
钩子是 React 16.8 版本引入的,它允许我们在函数组件中执行副作用操作。useEffect
函数接收两个参数:
- 一个副作用函数。
- 一个依赖项数组(可选)。
基本语法如下:
useEffect(() => {
// 副作用逻辑
return () => {
// 清除逻辑(可选)
};
}, [依赖项]);
二、useEffect 的基本用法
1. 无依赖项
如果不传递依赖项数组,副作用函数会在每次渲染后执行。
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
console.log('组件渲染或更新了');
return () => {
console.log('组件卸载了');
};
});
return <div>Hello, useEffect!</div>;
}
上述代码中,console.log
会在每次组件渲染或更新时执行,而返回的清除函数会在组件卸载时执行。
2. 空依赖项数组
如果传递一个空数组作为依赖项,副作用函数只会在组件首次渲染时执行一次。
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
console.log('组件首次渲染');
return () => {
console.log('组件卸载');
};
}, []);
return <div>Hello, useEffect!</div>;
}
3. 带依赖项的 useEffect
如果传递一个依赖项数组,副作用函数会在依赖项发生变化时执行。
import React, { useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Count 发生变化: ${count}`);
return () => {
console.log(`清除副作用: ${count}`);
};
}, [count]);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>增加</button>
</div>
);
}
上述代码中,当 count
发生变化时,副作用函数会执行,同时会先执行上一次渲染中的清除函数。
三、useEffect 的常见应用场景
1. 数据获取
在函数组件中使用 useEffect
可以方便地进行数据获取。
import React, { useState, useEffect } from 'react';
function DataFetchingComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
// 清除逻辑
return () => {
// 取消请求或其他清除操作
};
}, []); // 空依赖数组表示只在组件挂载和卸载时执行
if (!data) {
return <div>Loading...</div>;
}
return <div>{JSON.stringify(data)}</div>;
}
2. 订阅与清除
useEffect
也可以用于设置和清除订阅,例如事件监听器或 WebSocket 连接。
import React, { useEffect } from 'react';
function EventListenerComponent() {
useEffect(() => {
const handleResize = () => {
console.log('窗口大小改变');
};
window.addEventListener('resize', handleResize);
// 清除逻辑
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); // 空依赖数组表示只在组件挂载和卸载时执行
return <div>请调整窗口大小查看效果</div>;
}
3. 动画与定时器
我们可以使用 useEffect
来设置和清除定时器或启动动画。
import React, { useState, useEffect } from 'react';
function TimerComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setCount(prevCount => prevCount + 1);
}, 1000);
// 清除逻辑
return () => {
clearInterval(intervalId);
};
}, []); // 空依赖数组表示只在组件挂载和卸载时执行
return <div>计数: {count}</div>;
}
四、useEffect 的进阶用法
1. 多个 useEffect
在一个组件中可以使用多个 useEffect
,每个 useEffect
可以负责不同的副作用操作。
import React, { useState, useEffect } from 'react';
function MultiEffectComponent() {
const [count, setCount] = useState(0);
const [data, setData] = useState(null);
useEffect(() => {
document.title = `计数: ${count}`;
}, [count]);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}, []);
return (
<div>
<p>计数: {count}</p>
<button onClick={() => setCount(count + 1)}>增加</button>
<div>数据: {JSON.stringify(data)}</div>
</div>
);
}
2. 条件执行副作用
通过条件判断,可以有选择地执行副作用逻辑。
import React, { useState, useEffect } from 'react';
function ConditionalEffectComponent() {
const [count, setCount] = useState(0);
const [fetchData, setFetchData] = useState(false);
const [data, setData] = useState(null);
useEffect(() => {
if (fetchData) {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}
}, [fetchData]);
return (
<div>
<p>计数: {count}</p>
<button onClick={() => setCount(count + 1)}>增加</button>
<button onClick={() => setFetchData(true)}>获取数据</button>
<div>数据: {JSON.stringify(data)}</div>
</div>
);
}
五、注意事项
- 避免不必要的副作用:确保副作用函数只在需要时执行。使用依赖项数组来控制副作用的执行时机,避免不必要的重复执行。
- 清除副作用:副作用函数返回的清除函数用于清理不再需要的副作用。例如,清除事件监听器、取消订阅或清除定时器等。
- 依赖项数组:准确指定依赖项数组中的变量,确保副作用函数在依赖项发生变化时正确执行。遗漏或误包含依赖项可能导致副作用执行不符合预期。
- 处理异步操作:在处理异步操作时,注意在组件卸载时取消未完成的请求,避免内存泄漏。
- 性能优化:对于性能敏感的操作,确保合理使用
useEffect
,避免过度渲染和不必要的副作用执行。
推荐:JavaScript