React Hooks 钩子

发布于:2025-09-08 ⋅ 阅读:(15) ⋅ 点赞:(0)

React Hooks 是 React 16.8 引入的重要特性,让函数组件能够拥有类组件的状态和生命周期能力。以下是 React 官方提供的所有内置 Hooks,按功能分类整理,附带核心用法和场景说明:

一、基础 Hooks(最常用)

  • useState
  • 功能:为函数组件添加状态管理。
const [count, setCount] = useState(0); // 初始值为0
// 更新状态(直接赋值或函数式更新)
setCount(prev => prev + 1); 
  • 场景:管理组件内部的简单状态(如表单输入、开关状态等)。

useEffect

  • 功能:处理组件的副作用(如数据请求、订阅、DOM 操作),替代类组件的生命周期。
  • 用法
// 组件挂载和更新时执行(依赖项变化才触发)
useEffect(() => {
  const timer = setInterval(() => setCount(c => c + 1), 1000);
  // 清理函数(组件卸载或依赖变化前执行)
  return () => clearInterval(timer); 
}, []); // 空依赖:只在挂载和卸载时执行
  • 场景:数据加载、事件监听、定时器等需要 “副作用” 的操作。

useContext

  • 功能:跨组件共享数据,避免 “props drilling”(层层传递 props)。
  • 用法
// 先创建 Context
const ThemeContext = createContext('light');
// 在组件中获取 Context 值
const theme = useContext(ThemeContext); 

场景:全局状态(如主题、用户信息)在多层组件中的共享

二、额外的 Hooks(处理复杂场景)

  1. useReducer
  2. 功能:通过 reducer 管理复杂状态逻辑,类似 Redux 的简化版
// 定义 reducer 函数(状态更新规则)
function todoReducer(state, action) {
  switch(action.type) {
    case 'ADD': return [...state, action.payload];
    default: return state;
  }
}
// 在组件中使用
const [todos, dispatch] = useReducer(todoReducer, []);
// 触发更新
dispatch({ type: 'ADD', payload: '学习 Hooks' });
  • 场景:状态逻辑复杂(多值关联、多操作类型)或需要通过子组件修改父组件状态。

2、useCallback

功能:缓存函数,避免因函数重新创建导致子组件不必要的重渲染

// 缓存 handleClick 函数,依赖项不变则函数引用不变
const handleClick = useCallback(() => {
  console.log('点击了', count);
}, [count]); // 依赖 count,count 变则函数重新创建

3、useMemo

  • 功能:缓存计算结果,避免每次渲染重复执行耗时计算。
// 缓存计算结果,依赖项不变则直接返回缓存值
const total = useMemo(() => {
  return list.reduce((sum, item) => sum + item.price, 0);
}, [list]); // 依赖 list,list 变则重新计算
  • 场景:复杂计算(如大数据列表过滤、排序)。

4、useRef

  • 功能:创建一个可变的 ref 对象,可用于访问 DOM 元素或存储跨渲染周期的数据。
// 访问 DOM 元素
const inputRef = useRef(null);
useEffect(() => inputRef.current.focus(), []);

// 存储跨渲染的数据(修改不会触发重渲染)
const timerRef = useRef(null);
timerRef.current = setInterval(...);

5、useImperativeHandle

  • 功能:自定义通过 ref 暴露给父组件的实例值,限制子组件暴露的接口。
function ChildComponent(props, ref) {
  const inputRef = useRef(null);
  // 只暴露 focus 方法给父组件
  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus()
  }));
  return <input ref={inputRef} />;
}
// 父组件通过 ref 调用子组件暴露的方法
const childRef = useRef(null);
childRef.current.focus(); 
  • 场景:父组件需要操作子组件 DOM,但希望限制访问范围(避免过度耦合)。

6、useLayoutEffect

  • 功能:与 useEffect 类似,但回调函数在 DOM 更新后同步执行(而 useEffect 是异步)。
useLayoutEffect(() => {
  // 读取 DOM 布局并立即修改(避免页面闪烁)
  const { height } = elementRef.current.getBoundingClientRect();
  elementRef.current.style.marginTop = `${100 - height}px`;
}, []);
  • 场景:需要在 DOM 更新后立即读取布局信息并修改(如避免因样式计算导致的闪烁)。

7、useDebugValue

  • 功能:在 React DevTools 中为自定义 Hook 显示标签,方便调试。
function useFriendStatus(friendId) {
  const [isOnline, setIsOnline] = useState(null);
  // 在 DevTools 中显示 "FriendStatus: 在线/离线"
  useDebugValue(isOnline ? '在线' : '离线');
  return isOnline;
}
  • 场景:开发自定义 Hook 时,提升调试体验。

三、React 18+ 新增 Hooks(并发特性相关)

  1. useTransition
    功能:标记非紧急更新,避免阻塞用户交互(如输入、点击)。
const [isPending, startTransition] = useTransition();
// 紧急更新:立即响应输入
setInput(e.target.value);
// 非紧急更新:标记为过渡任务
startTransition(() => {
  setFilteredList(filterData(e.target.value)); // 耗时操作
});
  • 场景:输入搜索、列表筛选等需要 “优先响应输入,延迟处理结果” 的场景。

2、useDeferredValue

功能:为状态创建一个 “延迟版本”,优先保证 UI 响应速度

const [input, setInput] = useState('');
// 延迟版本:input 更新后,deferredInput 会“滞后”更新
const deferredInput = useDeferredValue(input);
// 基于延迟值渲染(避免输入时卡顿)
return <List data={filter(deferredInput)} />;
  • 场景:与 useTransition 类似,简化非紧急状态的处理。

3、useId

功能:生成跨服务器和客户端的唯一 ID,用于表单关联、无障碍访问(ARIA)

const id = useId(); // 生成如 "r1:2" 的唯一ID
return (
  <div>
    <label htmlFor={`${id}-name`}>姓名</label>
    <input id={`${id}-name`} />
  </div>
);
  • 场景:避免 SSR(服务器渲染)时客户端与服务器 ID 不匹配的问题。

4、useSyncExternalStore

  • 功能:同步外部状态(如 Redux、localStorage),确保在并发渲染中状态一致性。
// 从外部 store 读取状态
const state = useSyncExternalStore(
  store.subscribe, // 订阅状态变化
  store.getState,  // 获取当前状态
  store.getServerState // 服务器初始状态(SSR用)
);
  • 场景:集成外部状态管理库(如替代 Redux 的 useSelector)。

5、useInsertionEffect

  • 功能:在 CSS-in-JS 库中插入样式时使用,确保样式在 DOM 元素渲染前生效。
  • 用法:类似 useLayoutEffect,但执行时机更早(在 DOM 突变前)。
  • 场景:主要供 CSS-in-JS 库内部使用,普通开发很少直接用到。

网站公告

今日签到

点亮在社区的每一天
去签到