当前位置: 首页 > news >正文

React常见的Hooks

React Hooks 是 React 16.8 引入的特性,允许你在函数组件中使用状态和其他 React 特性。以下是 React 中主要的 Hooks 分类和具体用法:

一、基础Hooks

1、useState:

  • 在函数中添加状态管理
  • 返回一个状态值和一个更新状态的函数
import { useState } from 'react';function Counter() {const [count, setCount] = useState(0);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}

2、useEffect:

  • 处理副作用(数据获取、订阅、手动修改DOM等)
  • 可以模拟 componentDidMount、componentDidUpdate 和 componentWillUnmount
import { useState, useEffect } from 'react';function Example() {const [data, setData] = useState(null);useEffect(() => {fetch('https://api.example.com/data').then(res => res.json()).then(data => setData(data));return () => {// 清理函数(如取消订阅)};}, []); // 空数组表示只在组件挂载时运行一次
}

3、useContext:访问React中的上下文(Context),避免多层 props 传递。

import { useContext } from 'react';
const ThemeContext = React.createContext('light');function ThemedButton() {const theme = useContext(ThemeContext);return <button style={{ background: theme === 'dark' ? '#333' : '#eee' }}>按钮</button>;
}

二、额外Hooks

4、useReducer:复杂状态逻辑管理(类似Redux)

useReducer 基本语法:

const [state, dispatch] = useReducer(reducer, initialState, initFunction);

参数说明:

  • reducer:一个函数,形式为(state,antion)=> newState
  • initialStata:状态初始值
  • initFunction(可选):用于惰性初始化状态的函数

工作原理:

  • 组件通过dispatch(action)发出动作
  • React调用reducer(currentState,action)计算新状态
  • 组件使用新状态重新渲染
import { useReducer } from 'react';function reducer(state, action) {switch (action.type) {case 'increment':return { count: state.count + 1 };default:throw new Error();}
}function Counter() {const [state, dispatch] = useReducer(reducer, { count: 0 });return (<>Count: {state.count}<button onClick={() => dispatch({ type: 'increment' })}>+</button></>);
}

5、useRef:访问DOM节点或保存可变值(不会触发重新渲染)

访问DOM节点:

const inputRef = useRef(null);
<input ref={inputRef} />

保存可变值:创建可变引用,修改其值不会触发更新

import { useRef } from 'react';function Counter() {const countRef = useRef(0); // 初始化值为0const handleClick = () => {countRef.current += 1;    // 修改ref值不会触发重新渲染console.log(countRef.current);};return <button onClick={handleClick}>点击</button>;
}

特点:

  • 不会触发重新渲染:修改 .current属性,不会导致组件重新渲染
  • 跨渲染周期保持值:在组件的整个生命周期中保持同一个引用
  • 与实例变量类似:类似于类组件中的this.xxx属性

常见使用场景:

1、访问DOM元素

function TextInput() {const inputRef = useRef(null);const focusInput = () => {inputRef.current.focus(); // 访问DOM元素};return (<><input ref={inputRef} type="text" /><button onClick={focusInput}>聚焦输入框</button></>);
}

2、保存可变值(不触发重新渲染)

function Timer() {const countRef = useRef(0);const [dummy, setDummy] = useState(0); // 用于强制渲染useEffect(() => {const id = setInterval(() => {countRef.current += 1; // 修改ref值console.log(countRef.current);// 每5次更新一次UIif (countRef.current % 5 === 0) {setDummy(d => d + 1);}}, 1000);return () => clearInterval(id);}, []);return <div>计数: {countRef.current}</div>;
}

3、保存上一次值

function Counter() {const [count, setCount] = useState(0);const prevCountRef = useRef();useEffect(() => {prevCountRef.current = count; // 在渲染后更新ref}); // 没有依赖数组,每次渲染后都执行return (<div><p>当前: {count}, 之前: {prevCountRef.current}</p><button onClick={() => setCount(c => c + 1)}>增加</button></div>);
}

与useState区别:

特性useRefuseState
触发重新渲染
值存储位置返回对象的.current属性直接返回状态值
更新方式直接修改.current必须通过setState函数
使用场景需要保持可变但不触发渲染的值需要触发UI更新的状态

4、高级用法-在useCallback中使用ref

function Form() {const [value, setValue] = useState('');const valueRef = useRef(value);useEffect(() => {valueRef.current = value; // 同步value到ref}, [value]);const handleSubmit = useCallback(() => {console.log('提交的值:', valueRef.current); // 总是获取最新值}, []); // 不需要依赖valuereturn (<form onSubmit={handleSubmit}><input value={value} onChange={e => setValue(e.target.value)} /></form>);
}

5、实现组件实例方法

function FancyInput(props, ref) {const inputRef = useRef();useImperativeHandle(ref, () => ({focus: () => {inputRef.current.focus();},scrollIntoView: () => {inputRef.current.scrollIntoView();}}));return <input ref={inputRef} />;
}const ForwardedFancyInput = forwardRef(FancyInput);// 父组件使用
function Parent() {const inputRef = useRef();const handleClick = () => {inputRef.current.focus(); // 调用子组件方法};return (<><ForwardedFancyInput ref={inputRef} /><button onClick={handleClick}>聚焦输入框</button></>);
}

注意事项:

1、不要在渲染期间写入ref

// ❌ 错误写法
function MyComponent() {const myRef = useRef();myRef.current = 123; // 渲染期间修改refreturn ...;
}// ✅ 正确写法
function MyComponent() {const myRef = useRef(123); // 初始化时设置useEffect(() => {myRef.current = 456; // 在effect中修改}, []);return ...;
}

2、与 useEffect 配合使用时注意时序:

useEffect(() => {// 这里的ref.current可能不是最新的
}, []);useEffect(() => {// 更好的做法是在依赖数组中包含ref.current
}, [ref.current]);

6、useMemo:性能优化、缓存计算结果

useMemo 是 React 提供的一个性能优化 Hook,用于缓存计算结果,避免在每次渲染时都进行高开销的计算

基本语法:

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

参数说明:

  • 计算函数:返回需要缓存的值
  • 依赖数组:只有依赖变化的时候,才会重新计算值

常见场景:

1、复杂计算优化

const sortedList = useMemo(() => {return largeList.sort((a, b) => a.value - b.value);
}, [largeList]);

2、避免子组件不必要的渲染

const childProps = useMemo(() => ({ value: props.value }), [props.value]);
return <Child {...childProps} />;

3、引用类型稳定性

const config = useMemo(() => ({color: theme === 'dark' ? 'white' : 'black',size: 'large'
}), [theme]);

错误写法:

缺少依赖项

const badExample = useMemo(() => a + b, [a]); // 缺少b依赖

副作用操作

// 不应该在useMemo中执行副作用
useMemo(() => {fetchData(); // ❌ 副作用应放在useEffect中
}, []);

总是重新计算

// 空依赖数组表示只计算一次
const once = useMemo(() => compute(a), []); 
// 如果a可能变化,这会导致使用过期值

注意:

  • 所有回调函数内部用到的变量都必须包含在依赖数组中
  • 故意省略依赖是危险的,会导致缓存失效或使用过期值
  • 如果发现需要省略某些依赖,通常意味着代码结构需要重构

7、useCallback:缓存函数,避免不必要的重新渲染 从而优化性能

useCallback 会返回一个记忆化(memoized)的回调函数,只有当依赖项发生变化时才会重新创建函数。它的主要用途是:

  • 避免子组件不必要的重新渲染(配合 React.memo 使用)
  • 保持函数引用稳定,避免作为依赖项触发不必要的 effect 执行
  • 优化性能敏感的场景(如高频触发的事件处理)

基本语法:

const memoizedCallback = useCallback(
() => {
// 函数逻辑
},
[dep1, dep2], // 依赖项数组
);

典型使用场景:

1、避免子组件不必要的重新渲染

// 子组件
const Child = React.memo(function Child({ onClick }) {console.log('Child 渲染');return <button onClick={onClick}>点击</button>;
});// 父组件
function Parent() {const [count, setCount] = useState(0);// 使用useCallback缓存函数const handleClick = useCallback(() => {console.log('点击处理');}, []); // 空依赖表示函数永远不会改变return (<div><Child onClick={handleClick} /><button onClick={() => setCount(c => c + 1)}>计数: {count}</button></div>);
}

效果:当父组件状态更新时,Child 组件不会重新渲染,因为 onClick 的引用保持不变。

http://www.lryc.cn/news/620078.html

相关文章:

  • 万字详解C++11列表初始化与移动语义
  • OpenCV的实际应用
  • 类和对象----中
  • 【COMSOL】Comsol学习案例时的心得记录分享
  • Mysql数据库迁移到GaussDB注意事项
  • pycharm配置连接服务器
  • 3.Cursor提效应用场景实战
  • MySQL相关概念和易错知识点(6)(视图、用户管理)
  • 大厂语音合成成本深度对比:微软 / 阿里 / 腾讯 / 火山 API 计费拆解与技术选型指南
  • trace分析之查找点击事件
  • cisco无线WLC flexconnect配置
  • python类--python011
  • 数仓建模理论-数据域和主题域
  • 8.13服务器安全检测技术和防御技术
  • 免费生成视频,Coze扣子工作流完全免费的视频生成方案,实现图生视频、文生视频
  • [ Mybatis 多表关联查询 ] resultMap
  • LeetCode Day5 -- 二叉树
  • 使用 HTML5 Canvas 打造炫酷的数字时钟动画
  • Kubernetes-03:Service
  • 对线面试官之幂等和去重
  • 【OpenGL】LearnOpenGL学习笔记07 - 摄像机
  • 会议征稿!IOP出版|第二届人工智能、光电子学与光学技术国际研讨会(AIOT2025)
  • 【Android】RecyclerView多布局展示案例
  • [系统架构设计师]架构设计专业知识(二)
  • Linux 计划任务
  • 《书写范式》——代码如诗,诗娟代码(Python)(附精巧“九九表”生成代码)
  • Coze Studio 概览(十)--文档处理详细分析
  • k8s资源管理
  • 【android bluetooth 协议分析 05】【蓝牙连接详解3】【app侧该如何知道蓝牙设备的acl状态】
  • 如何理解vue组件失活与激活及导航全流程