新手到老鸟😎🚀玩转 React Effect

前言

想象一下,你在用 React 写一个网页,想让它在打开时自动播放一段视频,或者从服务器加载最新消息。这些"动态魔法"靠什么实现?答案就是 React 的 Effect!它就像一个超级助手,能帮你的组件跟外面的世界(比如浏览器、服务器)打交道。

但这个助手也有点调皮:用得好,页面丝滑又高效;用得不好,可能让你的代码卡顿甚至出错。

这篇文章会带你从零开始认识 Effect,学会怎么用它,还能避开那些常见的"坑"。


正文

是什么?

在 React 里,组件有两种主要任务:

  • 画页面:比如显示文字、按钮,这些是"纯计算",不会改变外界。
  • 处理点击:用户点一下按钮,触发一个动作,比如弹出提示。

但有些事跟"画页面"和"点击"都没关系,比如页面一打开就自动加载数据。这时候,Effect 上场了!看看这个例子:

javascript 复制代码
import { useEffect } from "react";

function ChatBox() {
  useEffect(() => {
    const connection = createConnection(); // 创建一个聊天连接
    connection.connect(); // 连接服务器

    return () => connection.disconnect(); // 离开时断开
  }, []);

  return <div>聊天室加载中...</div>;
}
  • 点击:用户点一下才跑。
  • Effect:组件一"出生"(渲染)就跑。

怎么用?

1、第一步:写一个 Effect

假设你做个视频播放器,想控制播放和暂停:

javascript 复制代码
import { useEffect, useRef } from "react";

function VideoPlayer({ isPlaying }) {
  const video = useRef(null);

  useEffect(() => {
    if (isPlaying) {
      video.current.play(); // 播放
    } else {
      video.current.pause(); // 暂停
    }
  });

  return <video ref={video} src="movie.mp4" />;
}

2、第二步:告诉它啥时候跑

如果不加限制,Effect 每次渲染都会跑,太浪费!加个"依赖项" [isPlaying],只有 isPlaying 变了才跑:

javascript 复制代码
useEffect(() => {
  if (isPlaying) {
    video.current.play();
  } else {
    video.current.pause();
  }
}, [isPlaying]); // 依赖 isPlaying

3、第三步:收拾"残局"

有些 Effect 会留下"垃圾",比如定时器,得清理掉:

javascript 复制代码
useEffect(() => {
  const timer = setInterval(() => {
    console.log("滴答滴答...");
  }, 1000);

  return () => clearInterval(timer); // 清理定时器
}, []);

为啥跑了两次?

开发模式下可能发现 Effect 跑了两次,别慌!这是 React 的"压力测试",故意让你检查清理代码写得对不对。只要清理函数没问题,线上就不会多跑。

解决办法:每次 Effect 都要有"撤回"动作,比如断开连接、清除定时器。

啥时候不用?

别啥都塞进 Effect,有些事更简单:

  • 算个数值 :直接写在组件里,比如 const total = price * count;
  • 用户点按钮 :用 onClick,别用 Effect。
  • 程序刚启动:放外面,比如:
javascript 复制代码
if (typeof window !== "undefined") {
  console.log("程序启动啦!");
}

实战

控制组件

想用 React 控制一个地图插件(非 React 写的):

javascript 复制代码
useEffect(() => {
  const map = mapRef.current;
  map.setZoomLevel(zoomLevel); // 调整地图缩放
}, [zoomLevel]);

加载数据

从服务器拿数据,小心别拿错了:

javascript 复制代码
useEffect(() => {
  let ignore = false;

  async function getData() {
    const data = await fetch("https://api.example.com/data");
    if (!ignore) setData(data); // 只用最新数据
  }

  getData();

  return () => {
    ignore = true; // 取消旧请求
  };
}, [url]);

搞点动画

让元素淡入淡出:

javascript 复制代码
useEffect(() => {
  const box = ref.current;
  box.style.opacity = 1; // 淡入

  return () => {
    box.style.opacity = 0; // 淡出
  };
}, []);

避坑指南

别乱跑 :依赖项写全,少跑几次。
稳住函数 :用 useCallback 包一下,避免依赖老变。
小心比赛 :异步操作可能乱序,用"取消标记"管好。
别卡页面:别在 Effect 里算太复杂的东西。

1、别把自己绕晕了

这个会无限循环:

javascript 复制代码
useEffect(() => {
  setCount(count + 1); // 改状态,又触发 Effect,死循环!
}, [count]);

改成这样:

javascript 复制代码
useEffect(() => {
  setCount((c) => c + 1); // 一次就够
}, []); // 空依赖,只跑一次

2、数据"过期"了

点一下按钮,打印的值可能是旧的:

javascript 复制代码
useEffect(() => {
  function handleClick() {
    console.log(count); // 可能不是最新的
  }
  window.addEventListener("click", handleClick);

  return () => window.removeEventListener("click", handleClick);
}, [count]); // 加 count,保证最新

3、请求乱了套

两个请求抢着更新:

javascript 复制代码
useEffect(() => {
  let cancelled = false;

  async function fetchData() {
    const result = await fetch(url);
    if (!cancelled) setData(result); // 只用没取消的
  }

  fetchData();

  return () => {
    cancelled = true;
  };
}, [url]);

总结

Effect 是 React 的"外挂",能让你的组件跟外界互动。记住这几招:

  • 少用为妙:能不用就不用。
  • 写清依赖:让 Effect 只在该跑时跑。
  • 收拾干净:别留垃圾。
  • 分清任务:一个 Effect 干一件事。
  • 别卡住:保持页面流畅。
相关推荐
这是个栗子1 小时前
【问题解决】npm包下载速度慢
前端·npm·node.js
Komorebi_99991 小时前
数组和对象的深拷贝和浅拷贝的方法
前端·web
weixin_584121431 小时前
vue3+ts+elementui-表格根据相同值合并
前端·javascript·elementui
吃手机用谁付的款2 小时前
HTML常见标签
前端·html
好好研究2 小时前
CSS样式中的布局、字体、响应式布局
前端·css
拉不动的猪4 小时前
前端小白之 CSS弹性布局基础使用规范案例讲解
前端·javascript·css
伍哥的传说4 小时前
React强大且灵活hooks库——ahooks入门实践之开发调试类hook(dev)详解
前端·javascript·react.js·ecmascript·hooks·react-hooks·ahooks
界面开发小八哥4 小时前
界面控件Kendo UI for Angular 2025 Q2新版亮点 - 增强跨设备的无缝体验
前端·ui·界面控件·kendo ui·angular.js
枷锁—sha5 小时前
从零掌握XML与DTD实体:原理、XXE漏洞攻防
xml·前端·网络·chrome·web安全·网络安全
F2E_Zhangmo5 小时前
基于cornerstone3D的dicom影像浏览器 第二章,初始化页面结构
前端·javascript·vue·cornerstone3d·cornerstonejs