React useEffect 使用场景示例

React 的 useEffect 是用于处理副作用(如数据获取、订阅、手动 DOM 操作等)的 Hook。以下是几个常见使用场景的示例:


1. 组件挂载时获取数据

jsx 复制代码
import { useEffect, useState } from 'react';

function DataFetcher() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    // 定义一个异步函数
    const fetchData = async () => {
      try {
        const response = await fetch('https://api.example.com/data');
        const result = await response.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    // 清理函数(可选,比如取消请求)
    return () => {
      // 可以在这里取消未完成的请求
    };
  }, []); // 空依赖数组:仅在组件挂载时运行一次

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <div>
      {data.map(item => <div key={item.id}>{item.name}</div>)}
    </div>
  );
}

2. 依赖项触发副作用

当某个值(如 count)变化时更新文档标题:

jsx 复制代码
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]); // 依赖项为 count,当 count 变化时触发

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

3. 添加和移除事件监听器

监听窗口大小变化:

jsx 复制代码
function WindowSizeTracker() {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    const handleResize = () => {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    window.addEventListener('resize', handleResize);

    // 清理函数:组件卸载时移除事件监听
    return () => {
      window.removeEventListener('resize', handleResize);
    };
  }, []); // 空依赖数组:仅在组件挂载和卸载时运行

  return (
    <div>
      Window size: {windowSize.width} x {windowSize.height}
    </div>
  );
}

4. 定时器(setInterval)

每秒更新一次时间:

jsx 复制代码
function Timer() {
  const [time, setTime] = useState(new Date());

  useEffect(() => {
    const timerId = setInterval(() => {
      setTime(new Date());
    }, 1000);

    // 清理函数:组件卸载时清除定时器
    return () => clearInterval(timerId);
  }, []); // 空依赖数组:定时器只初始化一次

  return <div>Current time: {time.toLocaleTimeString()}</div>;
}

5. 依赖项为空 vs 无依赖

  • 空依赖数组 []:仅在组件挂载时运行一次。
  • 无依赖数组:每次组件渲染后都会运行。
  • 特定依赖 [dep1, dep2]:当依赖项变化时运行。

注意事项

  1. 避免无限循环 :如果依赖项是引用类型(如对象或数组),需确保它们的引用稳定(比如使用 useMemo)。

  2. 异步操作 :直接在 useEffect 中使用 async 函数会报错,但可以在内部定义 async 函数并调用:

    jsx 复制代码
    useEffect(() => {
      const fetchData = async () => { /* ... */ };
      fetchData();
    }, []);
  3. 清理副作用:始终为需要清理的操作(如事件监听、定时器)返回清理函数。

通过合理使用 useEffect,可以管理组件的生命周期和副作用逻辑。

相关推荐
山楂树の18 分钟前
图像标注大坑:img图片 + Canvas 叠加标注,同步放大后标注位置偏移、对不齐?详解修复方案及亚像素处理原理
前端·css·学习·canva可画
本山德彪20 分钟前
我做了一个拼豆图纸生成器,把照片秒变图纸
前端
DTrader1 小时前
用TS无法实盘量化? - 实盘均线策略
前端·api
进击的夸父1 小时前
vfojs:Vue 超集架构,外壳React灵魂Vue
前端
编程老船长1 小时前
解决不同项目需要不同 Node.js 版本的问题
前端·vue.js
Wect1 小时前
LeetCode 5. 最长回文子串:DP + 中心扩展
前端·算法·typescript
漫游的渔夫1 小时前
前端开发者做 Agent:别写成一次请求,用 5 步受控循环防止 AI 乱跑
前端·人工智能·typescript
kyriewen2 小时前
Webpack vs Vite:一个是“老黄牛”,一个是“猎豹”,你选谁?
前端·webpack·vite
打小就很皮...2 小时前
html2canvas + jsPDF 生成 PDF 的踩坑与解决方案总结
前端·pdf
全栈前端老曹2 小时前
【前端地图】多地图平台适配方案——高德、百度、腾讯、Google Maps SDK 差异对比、封装统一地图接口
前端·javascript·百度·dubbo·wgs84·gcj-02·bd09