react的useState/useEffect/useRef/useMemo/useCallback/useContext/useReducer  用法+场景

0 阅读4分钟

React 常用 Hooks:用法 + 场景总结

React Hooks 是函数组件中管理“状态、生命周期、性能优化、组件通信”等能力的核心工具。


1. useState —— 状态管理(最常用)

用于:保存组件状态


基本用法

import { useState } from 'react';

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

  return (
    <div>
      <p>{count}</p>

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

核心理解

const [状态, 修改状态的方法] = useState(初始值)

特点

  • 修改状态会重新渲染组件
  • 状态更新是异步的
  • 不要直接修改状态

错误:

count = count + 1

正确:

setCount(count + 1)

场景

1)计数器

const [count, setCount] = useState(0)

2)表单输入

const [username, setUsername] = useState('');

<input
  value={username}
  onChange={(e) => setUsername(e.target.value)}
/>

3)弹窗开关

const [visible, setVisible] = useState(false)

2. useEffect —— 副作用处理

用于:
处理“组件渲染之外”的事情

比如:

  • 请求接口
  • 定时器
  • 事件监听
  • DOM 操作
  • 数据同步

生命周期理解

可以把它理解为:

componentDidMount
componentDidUpdate
componentWillUnmount

的组合版。


基本用法

useEffect(() => {
  console.log('组件渲染了');
});

默认:

  • 首次执行
  • 更新也执行

依赖数组


1)不写依赖

useEffect(() => {
  console.log('每次渲染都会执行');
});

场景:

  • 调试
  • 每次更新都同步

2)空数组 []

useEffect(() => {
  console.log('只执行一次');
}, []);

等价于:

componentDidMount

场景:

  • 页面初始化请求
  • 初始化图表
  • 初始化 websocket

3)有依赖

useEffect(() => {
  console.log('count变化了');
}, [count]);

只有:

count 改变

才执行。


清理函数(重点)

useEffect(() => {
  const timer = setInterval(() => {
    console.log('执行中');
  }, 1000);

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

return 的函数:

组件卸载时执行

用于:

  • 清除定时器
  • 移除事件
  • 取消订阅
  • 关闭 websocket

场景

请求接口

useEffect(() => {
  fetchData();
}, []);

监听窗口变化

useEffect(() => {
  const resize = () => console.log(window.innerWidth);

  window.addEventListener('resize', resize);

  return () => {
    window.removeEventListener('resize', resize);
  };
}, []);

3. useRef —— 保存引用

用途:

  • 获取 DOM
  • 保存变量(不会重新渲染)

获取 DOM

import { useRef } from 'react';

function App() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <>
      <input ref={inputRef} />

      <button onClick={focusInput}>
        聚焦
      </button>
    </>
  );
}

保存变量(不会触发更新)

const countRef = useRef(0);

countRef.current++;

特点:

  • 修改不会重新渲染
  • 类似实例变量

useRef vs useState

对比useStateuseRef
修改后重新渲染不会
适合 UI 数据
保存临时变量不推荐推荐

场景

防抖节流 timer

const timerRef = useRef(null)

保存上一次值

const prevValue = useRef();

操作 DOM

inputRef.current.focus()

4. useMemo —— 缓存计算结果

用于:

避免重复计算

基本用法

const total = useMemo(() => {
  return list.reduce((a, b) => a + b, 0);
}, [list]);

只有:

list 变化

才重新计算。


为什么需要?

例如:

大量数据计算

每次 render 都重新执行会卡。

useMemo 可以缓存结果。


场景

大数据计算

const expensiveValue = useMemo(() => {
  return heavyCompute(data);
}, [data]);

避免子组件重复渲染

const userInfo = useMemo(() => {
  return {
    name,
    age
  };
}, [name, age]);

否则:

{}

每次 render 都是新对象。


5. useCallback —— 缓存函数

用于:

缓存函数

基本用法

const handleClick = useCallback(() => {
  console.log('点击');
}, []);

为什么需要?

React 中:

函数每次 render 都会重新创建

可能导致:

子组件重复渲染

配合 memo 使用(重点)

父组件:

const handleAdd = useCallback(() => {
  console.log('add');
}, []);

<Child onAdd={handleAdd} />

子组件:

export default memo(Child)

这样:

父组件更新
不会导致子组件重新渲染

useMemo vs useCallback

Hook缓存什么
useMemo
useCallback函数

场景

传递函数给子组件

onClick
onChange
submit

防止重复渲染

特别是:

  • React.memo
  • 大列表
  • 复杂组件

6. useContext —— 跨组件通信

解决:

props 一层层传递

创建 Context

import { createContext } from 'react';

const ThemeContext = createContext();

Provider 提供数据

<ThemeContext.Provider value="dark">
  <App />
</ThemeContext.Provider>

子组件使用

import { useContext } from 'react';

const theme = useContext(ThemeContext);

场景

全局主题

dark/light

用户信息

登录用户

权限管理(RBAC)

比如:

role = admin

整个系统共享。


7. useReducer —— 复杂状态管理

适用于:

复杂 state 逻辑

类似 Redux。


基本用法

import { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'add':
      return {
        count: state.count + 1
      };

    case 'minus':
      return {
        count: state.count - 1
      };

    default:
      return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(reducer, {
    count: 0
  });

  return (
    <>
      <p>{state.count}</p>

      <button onClick={() =>
        dispatch({ type: 'add' })
      }>
        +1
      </button>
    </>
  );
}

核心理解

dispatch(action)
→ reducer处理
→ 返回新state

场景

表单复杂状态

多个输入框

多状态联动

loading
data
error

替代 Redux 小型场景

中小项目状态管理

Hooks 之间关系图

状态管理:
useState
useReducer

副作用:
useEffect

DOM/变量:
useRef

性能优化:
useMemo
useCallback

跨组件通信:
useContext

企业开发里最常用组合


页面请求

useState + useEffect

表单

useState/useReducer

权限系统(RBAC)

useContext

表格性能优化

useMemo + useCallback

Echarts 图表

(你之前做性能平台会很常见)

useRef + useEffect

初始化:

echarts.init(ref.current)

面试高频问题


1)为什么 useEffect 会重复执行?

因为:

组件重新 render

导致 effect 重新触发。


2)useMemo 一定能优化性能吗?

不一定。

因为:

缓存本身也有成本

小计算没必要。


3)为什么 useRef 不会触发更新?

因为:

它不参与 React 渲染

只是保存对象。


4)什么时候用 useReducer?

当:

state逻辑复杂
多个状态关联

时优于 useState。


一张总结表

Hook作用典型场景
useState状态管理表单、开关、计数
useEffect副作用请求接口、监听
useRefDOM/缓存变量input聚焦、timer
useMemo缓存值大计算
useCallback缓存函数子组件优化
useContext跨组件通信用户、主题、权限
useReducer复杂状态表单、Redux思想