React Hooks 编程:`useState` 和 `useEffect`,再不懂就OUT了!

✍️ 作者:我是一名前端小菜鸟,正在努力升级打怪中


前言

大家好,我是一名前端小菜鸟,平时和 console.log 相依为命,经常被报错支配。这篇文章想和同样在学习 React 的朋友分享一下我对 useStateuseEffect 的理解和使用方式。它们是函数式组件里最核心的两个 Hook,掌握了它们,写 React 真的会轻松很多。

今天咱们聊聊 React 的两大亲儿子 Hook:useStateuseEffect

如果说 React 是一艘游轮,那 Hooks 就是发动机和方向盘,别小看它俩,真整明白了,能让你写出优雅的函数式组件,不仅优雅,还能装X!


useState:状态的开关

咱先看 useState,这玩意儿到底是啥?

一句话:useState 就是个函数,让你在函数式组件里拥有自己的"记忆"。

在 JS 里,函数是一等公民

  • 可以当变量传递。
  • 可以 return 另一个函数。
  • 可以当作组件,return 出 JSX

上面这三点如若详细展开又可以写一篇文章了,我这里便以一个表格结束

特性 含义 React 场景
函数可以当变量传递 函数是值,可赋值、可传参 事件处理、父子通信
函数可以返回函数 返回新函数,形成闭包 自定义 Hook、生成事件处理
函数可以作为组件返回 JSX 函数式组件就是返回 JSX 函数组件结合 Hooks

所以当 React 团队给了函数式组件 useState 之后,类组件那一套冗长的 this.statethis.setState 就可以拜拜了。

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

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

  return (
    <div>
      <h1>我点了 {count} 次</h1>
      <button onClick={() => setCount(count + 1)}>点我+1</button>
    </div>
  );
}

是不是很丝滑?
useState 返回一个数组:

  • 第一个是当前状态值
  • 第二个是你用来更新它的函数

真·函数式,优雅到犯规。

如果更新需要依赖旧的状态则用useState的函数式更新

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

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

  const double = () => {
    setCount(prev => prev * 2);
  };

  return (
    <div>
      <p>当前:{count}</p>
      <button onClick={() => setCount(prev => prev + 1)}>+1</button>
      <button onClick={double}>×2</button>
    </div>
  );
}

setCount(prev=>...),保证每次更新都在最新状态,避免异步更新带来的状态不同步的问题

useEffect:副作用管理大师

有了 useState,你能在组件里存状态,那副作用呢?(比如请求接口、订阅事件、操作 DOM...)

这时候就轮到 useEffect 上场了!

什么是副作用?

简单说就是:除了渲染 UI,还要干别的,这就是副作用(side-effect)。

比如:

  • 请求接口
  • 监听滚动
  • 操作 document.title
  • 设置定时器

这些都不是纯渲染逻辑,需要在"对的时机"执行。


useEffect和生命周期的那些事

useEffect,你就相当于在写函数式组件里的生命周期函数。 什么是生命周期? 其实它包含三个阶段,如下所示

  1. 挂载(Mount): 组件第一次创建办并显示在页面上
  2. 更新(Updata):当组件状态或者属性发生改变时,会重新渲染页面
  3. 卸载(UnMount):当组件被移除时要清理定时器等,防止内存泄漏
  • 挂载后 执行(componentDidMount):useEffect(() => {}, [])
  • 更新后 执行(componentDidUpdate):useEffect(() => {}, [依赖])
  • 卸载前 清理(componentWillUnmount):useEffect 的返回函数

举个栗子:

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

function App() {
  useEffect(() => {
    console.log('组件挂载了!');

    return () => {
      console.log('组件卸载了!');
    };
  }, []);

  return <h1>Hello Hooks</h1>;
}

useEffect 做了三件事:

  1. 第一次渲染执行逻辑(console.log
  2. 如果依赖项没变化,不会重复执行
  3. 卸载时会执行 return 里的清理函数

这就是 React 的"自带扫地僧",帮你回收定时器、取消订阅、终止网络请求,防止内存泄漏。


什么时候请求接口最合适?

很多人问:请求接口放哪儿?

答案是:useEffect 里,依赖项写 []

这样:

  • 组件第一次挂载就执行
  • 不会和渲染抢时间(React 会等 DOM 先渲染完)
  • 状态更新时不会重复请求

示例:

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

function UserList() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    fetch('https://api.example.com/users')
      .then(res => res.json())
      .then(data => setUsers(data));
  }, []);

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

依赖项 [] 代表只在挂载时请求一次,状态变了也不重复跑。


🧙‍♂ useEffect 为啥不能直接 async

有朋友写:

scss 复制代码
jsx
复制编辑
useEffect(async () => {
  // ...
}, []);

报错了!为啥?

其实是因为useEffect 的回调必须返回一个函数或者啥也不返回,而 async 函数默认返回 Promise,这不符合要求。

咋办?套一层!

scss 复制代码
jsx
复制编辑
useEffect(() => {
  async function fetchData() {
    const res = await fetch('...');
    // ...
  }
  fetchData();
}, []);

要点

  • 外层是普通函数
  • 里头可以是 async
  • 需要清理的逻辑还是写在 return

卸载时的善后工作

别忘了:定时器、订阅、请求都要在组件卸载时手动清理。

javascript 复制代码
jsx
复制编辑
useEffect(() => {
  const timer = setInterval(() => {
    console.log('tick');
  }, 1000);

  return () => {
    clearInterval(timer);
  };
}, []);

用clearInterval()函数进行清理,防止内存泄漏

如果不清理?页面都没了,内存还在跑,等着爆炸吗?🤯


总结

useState:状态管理大师
useEffect:副作用掌控者 + 生命周期模拟器

两把神兵在手,函数式组件天下我有。


最后的小建议

  • 先想清楚"这段逻辑要不要每次都跑" ➡️ 合理写依赖项。
  • 不要乱写 async ➡️ 套个内部函数。
  • 做好善后 ➡️ 定时器/订阅/请求该清理就清理。

如果这篇对你有帮助,点个 再走吧!

有问题评论区见,我和 console.log 等你来约会

相关推荐
aklry8 分钟前
uniapp三步完成一维码的生成
前端·vue.js
Rubin9315 分钟前
判断元素在可视区域?用于滚动加载,数据埋点等
前端
爱学习的茄子16 分钟前
AI驱动的单词学习应用:从图片识别到语音合成的完整实现
前端·深度学习·react.js
用户38022585982416 分钟前
使用three.js实现3D地球
前端·three.js
程序无bug19 分钟前
Spring 面向切面编程AOP 详细讲解
java·前端
zhanshuo19 分钟前
鸿蒙UI开发全解:JS与Java双引擎实战指南
前端·javascript·harmonyos
JohnYan19 分钟前
模板+数据的文档生成技术方案设计和实现
javascript·后端·架构
撰卢43 分钟前
如何提高网站加载速度速度
前端·javascript·css·html
10年前端老司机1 小时前
在React项目中如何封装一个可扩展,复用性强的组件
前端·javascript·react.js
Struggler2811 小时前
解决setTimeout/setInterval计时不准确问题的方案
前端