1.React常用内置hook

1.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>
        <button onClick={() => setCount(prev => prev - 1)}>-1</button>
      </div>
   );
}

要点:

  • 初始值可以是 useState(() => expensiveInit()) 惰性初始化
  • 对象/数组更新要创建新引用:setUser({ ...user, name: 'Tom' })

1.2 useEffect — 副作用

作用:在渲染后执行副作用(请求数据、订阅、操作 DOM 等)。

import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
    const [user, setUser] = useState(null);
    useEffect(() => {
        let cancelled = false;
        fetch(`/api/users/${userId}`)
            .then(res => res.json())
            .then(data => {
                if (!cancelled){ 
                    setUser(data);
                }
            }
        );

        // 清理函数:组件卸载或依赖变化前执行
        return () => {
            cancelled = true;
        };
    }, [userId]); // 依赖数组:userId 变化时重新执行
    if (!user) return (
        <p>加载中...</p>
    );
    return (
        <h1>{user.name}</h1>
    );
}

依赖数组规则:

写法 行为

无依赖数组

每次渲染后都执行

[]

仅挂载时执行一次

[a, b]

a 或 b 变化时执行

1.3 useContext — 跨层级共享数据

作用:读取 Context,避免逐层 props 传递。

import { createContext, useContext, useState } from 'react';

const ThemeContext = createContext('light');

function App() {
    const [theme, setTheme] = useState('light');
    return (
        <ThemeContext.Provider value={{ theme, setTheme }}>
            <Toolbar />
        </ThemeContext.Provider>
    );

}

function Toolbar() {
    const { theme, setTheme } = useContext(ThemeContext);
    return (
        <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        当前主题: {theme}
        </button>
    );
}

1.4 useRef — 持久引用 / DOM 引用

作用:保存跨渲染不变的可变值;或获取 DOM 节点。改 .current 不会触发重渲染。

import { useRef, useEffect } from 'react';

function TextInput() {
    const inputRef = useRef(null);
    const renderCount = useRef(0);
    useEffect(() => {
        renderCount.current += 1;
        inputRef.current?.focus();
    });
    return (
       <>
        <input ref={inputRef} />
        <p>渲染次数: {renderCount.current}</p>
       </>
    );
}

1.5 useReducer — 复杂状态逻辑

作用:用 dispatch(action) 管理复杂状态,类似 Redux 思路。

import { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
    switch (action.type) {
        case 'increment': return { count: state.count + 1 };
        case 'decrement': return { count: state.count - 1 };
        case 'reset': return initialState;
        default: return state;
    }
}


function Counter() {
    const [state, dispatch] = useReducer(reducer, initialState);
    return (
      <>
        <p>{state.count}</p>
        <button onClick={() => dispatch({ type: 'increment' })}>+</button>
        <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      </>
    );
}

适合:多字段表单、状态机、下一步依赖上一步的更新。

1.6 useMemo — 缓存计算结果

作用:依赖不变时复用上次计算结果,减少昂贵运算。

import { useMemo, useState } from 'react';

function ProductList({ products, filter }) {
    const [sortOrder, setSortOrder] = useState('asc');
    const filtered = useMemo(() => {
        console.log('重新过滤...');
        return products
                .filter(p => p.name.includes(filter))
                .sort((a, b) => sortOrder === 'asc' ? a.price - b.price : b.price - a.price);
    }, [products, filter, sortOrder]);

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

1.7 useCallback — 缓存函数引用

作用:依赖不变时返回同一函数引用,常用于传给子组件或作为 useEffect 依赖。

import { useState, useCallback, memo } from 'react';

const Child = memo(function Child({ onClick }) {
    console.log('Child 渲染');
    return <button onClick={onClick}>点击</button>;
});

function Parent() {
     const [count, setCount] = useState(0);
     const [text, setText] = useState('');
     const handleClick = useCallback(() => {
       setCount(c => c + 1);
     }, []); // 不依赖外部变量,引用稳定

     return (
       <>
         <input value={text} onChange={e => setText(e.target.value)} />
         <Child onClick={handleClick} />
         <p>{count}</p>
       </>

     );
}

注意:不要滥用;只有子组件用了 memo 或函数作为依赖时才明显有用。

1.8.useLayoutEffect — 同步副作用

作用:与 useEffect 类似,但在浏览器绘制之前同步执行。适合测量 DOM、同步改样式,避免闪烁。

import { useLayoutEffect, useRef, useState } from 'react';

function Tooltip({ children }) {
    const ref = useRef(null);
    const [top, setTop] = useState(0);
    useLayoutEffect(() => {
        const rect = ref.current.getBoundingClientRect();
        setTop(rect.bottom + 8); // 在绘制前算好位置
    }, []);

    return (
        <div ref={ref}>
            {children}
            <div style={{ position: 'absolute', top }}>提示内容</div>
        </div>
    );

}

1.9 useId — 生成唯一 ID

作用:生成 SSR 安全的稳定 ID,用于 label / aria 关联。

import { useId } from 'react';

function EmailField() {
    const id = useId();
    return (
      <>
        <label htmlFor={id}>邮箱</label>
        <input id={id} type="email" aria-describedby={`${id}-hint`} />
        <span id={`${id}-hint`}>我们不会泄露你的邮箱</span>
      </>
    );
}

1.10 useImperativeHandle — 自定义暴露给父组件的 ref

作用:配合 forwardRef,只暴露部分方法给父组件。

import { forwardRef, useImperativeHandle, useRef } from 'react';
    
const FancyInput = forwardRef(function FancyInput(props, ref) {
    const inputRef = useRef(null);

    useImperativeHandle(ref, () => ({
        focus: () => inputRef.current?.focus(),
        clear: () => { inputRef.current.value = ''; },
    }));

    return <input ref={inputRef} {...props} />;
});

// 父组件
function Form() {
    const inputRef = useRef(null);
    return (
      <>
        <FancyInput ref={inputRef} />
        <button onClick={() => inputRef.current?.focus()}>聚焦</button>
      </>
    );
}

1.11 useTransition — 非紧急更新

作用:把状态更新标为非紧急,保持 UI 响应(如大列表筛选)。

import { useState, useTransition } from 'react';

function SearchList({ items }) {
    const [query, setQuery] = useState('');
    const [isPending, startTransition] = useTransition();
    const handleChange = (e) => {
        const value = e.target.value;
        setQuery(value); // 紧急:输入框立刻更新
        startTransition(() => {
          // 非紧急:列表过滤可以稍后
          setFiltered(items.filter(i => i.includes(value)));
        });

    };

    return (
       <>
          <input value={query} onChange={handleChange} />
          {isPending && <span>更新中...</span>}
       </>

    );
}

1.12 useDeferredValue — 延迟显示值

作用:延迟某值的更新,让更紧急的 UI 先渲染。

import { useState, useDeferredValue, memo } from 'react';

const SlowList = memo(function SlowList({ text }) {
    // 假设渲染很慢
    return <ul>{/* 大量项 */}</ul>;
});

function App() {
    const [text, setText] = useState('');
    const deferredText = useDeferredValue(text);
    return (
        <>
           <input value={text} onChange={e => setText(e.target.value)} />
           <SlowList text={deferredText} />
        </>
    );
}

1.13 useSyncExternalStore — 订阅外部数据源

作用:安全订阅浏览器 API 或外部 store(如 Redux)。

import { useSyncExternalStore } from 'react';

function useMediaQuery(query) {
    return useSyncExternalStore(
        (callback) => {
            const mq = window.matchMedia(query);
            mq.addEventListener('change', callback);
            return () => mq.removeEventListener('change', callback);

        },
        () => window.matchMedia(query).matches,
        () => false // SSR 回退值
    );
}

function Responsive() {
   const isMobile = useMediaQuery('(max-width: 768px)');
   return <p>{isMobile ? '移动端' : '桌面端'}</p>;
}

2. React 19 新增 Hook

2.1 useActionState(原 useFormState

处理表单 action 的状态(pending、返回值等)。

import { useActionState } from 'react';

async function submitForm(prevState, formData) {
    const name = formData.get('name');
    if (!name) return { error: '姓名不能为空' };
    await saveUser(name);
    return { success: true };
}

function MyForm() {
    const [state, formAction, isPending] = useActionState(submitForm, null);
    return (
       <form action={formAction}>
          <input name="name" />
          <button disabled={isPending}>{isPending ? '提交中...' : '提交'}</button>
          {state?.error && <p>{state.error}</p>}
       </form>

    );
}

2.2 useOptimistic — 乐观更新

import { useOptimistic, useState } from 'react';

function Messages({ messages, sendMessage }) {
    const [optimisticMessages, addOptimistic] = useOptimistic(
      messages,
      (state, newMsg) => [...state, { ...newMsg, sending: true }]
);

    async function handleSend(text) {
       addOptimistic({ id: Date.now(), text });
       await sendMessage(text);
    }

    return (
      <ul>
        {optimisticMessages.map(m => (
          <li key={m.id}>{m.text} {m.sending && '(发送中)'}</li>
        ))}
     </ul>
    );
}

2.3 use() — 读取 Promise 或 Context

import { use, Suspense } from 'react';

function User({ userPromise }) {
    const user = use(userPromise); // 需在 Suspense 边界内
    return <p>{user.name}</p>;
}

function App() {
  const userPromise = fetchUser(1);
  return (
    <Suspense fallback={<p>加载中...</p>}>
      <User userPromise={userPromise} />
    </Suspense>
  );
}

3. 总结和建议

3.1 快速对照表

Hook 一句话

useState

组件本地状态

useEffect

渲染后的副作用

useContext

读 Context

useRef

持久引用 / DOM

useReducer

复杂状态 + dispatch

useMemo

缓存计算结果

useCallback

缓存函数引用

useLayoutEffect

绘制前的同步副作用

useId

唯一 ID(SSR 安全)

useImperativeHandle

自定义 ref 暴露

useTransition

标记非紧急更新

useDeferredValue

延迟某值更新

useSyncExternalStore

订阅外部 store

useActionState

表单 action 状态

useOptimistic

乐观 UI 更新

use

读 Promise / Context

3.2 使用建议

  1. 默认用 useState + useEffect,复杂了再考虑 useReducer
  2. useMemo / useCallback 先别过早优化,有性能问题再加。
  3. useEffect 依赖要写全,避免闭包旧值和无限循环。
  4. 数据请求优先考虑 React Query / SWR,或 React 19 的 use + Server Components。
  5. 自定义 Hook 是把逻辑复用的最佳方式:把 useState + useEffect 等组合封装成 useXxx()

更多推荐