如何在 React 中正确实现自定义 useState Hook

12次阅读

如何在 React 中正确实现自定义 useState Hook

本文详解为何简单闭包无法复现 usestate 行为,并提供符合 react 更新机制的自定义 usecustomstate 实现方案,包含 useref + useeffect 的正确范式、可变状态同步原理及关键注意事项。

react 的 useState 不仅管理值,更核心的是触发组件重渲染。你原始代码的问题在于:value 是一个局部变量,setValue 仅修改了该变量,但未通知 React 触发更新——因此 ui 永远停留在初始值 3。

要真正模拟 useState,必须满足两个条件:

  1. 状态持久化:跨多次渲染保持最新值(不能每次调用 Hook 都重置);
  2. 触发重渲染:状态变更后,必须调用 setState 或等效机制(如 forceUpdate)驱动组件更新。

✅ 正确实现方式是借助 useRef 存储当前值 + useState(或 usereducer)驱动更新

import React, { useState, useRef, useCallback } from 'react';  const useCustomState = (initialState) => {   // 使用 useRef 持久化最新值(不触发渲染)   const valueRef = useRef(initialState);    // 使用 useState 控制渲染(真正的“驱动器”)   const [, forceUpdate] = useState({});    const setValue = useCallback((newVal) => {     // 同步更新 ref 值(供后续读取)     valueRef.current = typeof newVal === 'function'        ? newVal(valueRef.current)        : newVal;      // 触发重渲染(关键!)     forceUpdate({});   }, []);    // 返回当前 ref 值(始终是最新的)   return [valueRef.current, setValue]; };

? 使用示例(与原生 useState 完全一致)

function app() {   const [count, setCount] = useCustomState(3);    return (     <>       

{count}

); }

⚠️ 关键注意事项

  • ❌ 不要仅用普通变量(如 let value = …)存储状态——它会在每次渲染时重新声明,丢失上一次值;
  • ✅ useRef 是唯一能在不触发重渲染的前提下跨渲染保留值的机制;
  • ✅ useState(哪怕只用于 forceUpdate)是触发 UI 同步的必要桥梁
  • ✅ 使用 useCallback 包裹 setValue,避免每次渲染都生成新函数,防止子组件不必要的重渲染;
  • ? 支持函数式更新(setCount(prev => prev + 1)),通过 typeof newVal === ‘function’ 判断并执行;

? 延伸建议
实际项目中,无需重复造轮子。useState 本身已高度优化且支持所有场景(对象、数组、函数更新等)。若需封装逻辑(如表单状态、防抖 setState),应基于 useState 构建「带业务语义的 custom Hook」(例如 useFormState, useDebouncedState),而非试图“重写” useState 内核。

掌握其原理是为了深入理解 React 的状态模型,而非替代它——这才是自定义 Hook 的正确实践哲学。

text=ZqhQzanResources