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

react 常用钩子 hooks 总结

文章目录

          • React钩子概念图
            • 状态管理钩子 state management
            • 副作用钩子 effect hooks
            • 引用钩子 Ref hooks
            • 上下文钩子
            • 其他钩子
            • 过渡钩子 处理过渡效果
            • 性能优化钩子 performance hooks
            • React 19 新钩子


React钩子概念图
状态管理钩子 state management

useState useReducer useSyncExternalStore

useState 最常用钩子

const [value, setValue] = useState('')
const handleChange = (e) => {setValue(e.target.value)
}
<input type="text" value = {value} onChange = {handleChange}></input>
#捕获用户输入值的变化
import React, { useState } from 'react';function ToggleComponent() {const [isVisible, setIsVisible] = useState(false);return (<><button onClick={() => setIsVisible(!isVisible)}>Toggle</button>{isVisible && <div>Content to Show/Hide</div>}</>);
}export default ToggleComponent;
# 控制显隐

useReducer 管理更为复杂状态的钩子

在一个reducer函数内管理状态

import React, { useReducer } from 'react';// Reducer 函数
const reducer = (state, action) => {switch (action) {case 'increment':return state + 1;default:return state; // 默认返回当前状态}
};function Counter() {const [count, dispatch] = useReducer(reducer, 0);return (<><p>Count: {count}</p><button onClick={() => dispatch('increment')}>Increment</button></>);
}export default Counter;

这个其实有点类似 Vue 的 vuex 两者设计思想类似 学过这两种语言的应该会有感受

相似点

  1. 状态定义
    • useReducer 中,初始状态通过 useReducer(reducer, initialState) 定义。
    • 在 Vuex 中,初始状态通过 state 属性定义。
  2. 状态更新逻辑
    • useReducer 中,reducer 函数负责根据 action 计算新的状态。
    • 在 Vuex 中,mutations 是唯一可以修改状态的地方,类似于 reducer
  3. 触发状态更新
    • useReducer 中,通过 dispatch(action) 触发状态更新。
    • 在 Vuex 中,通过 commit('mutation')dispatch('action') 触发状态更新。
  4. 集中化管理
    • 两者都提供了一种集中化的方式管理状态,避免了组件内部直接操作状态的混乱。

代码对比

React useReducer

import React, { useReducer } from 'react';const initialState = 0;// Reducer 函数
const reducer = (state, action) => {switch (action.type) {case 'increment':return state + 1;case 'decrement':return state - 1;default:return state;}
};function Counter() {const [count, dispatch] = useReducer(reducer, initialState);return (<><p>Count: {count}</p><button onClick={() => dispatch({ type: 'increment' })}>Increment</button><button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button></>);
}export default Counter;

Vuex Store

// Vuex store
const store = new Vuex.Store({state: {count: 0,},mutations: {increment(state) {state.count++;},decrement(state) {state.count--;},},actions: {increment({ commit }) {commit('increment');},decrement({ commit }) {commit('decrement');},},
});// Vue 组件
<template><div><p>Count: {{ count }}</p><button @click="increment">Increment</button><button @click="decrement">Decrement</button></div>
</template><script>
export default {computed: {count() {return this.$store.state.count;},},methods: {increment() {this.$store.dispatch('increment');},decrement() {this.$store.dispatch('decrement');},},
};
</script>

主要区别

特性React useReducerVuex
作用范围适用于单个组件或父子组件间的状态管理适用于全局状态管理(跨多个组件)
触发方式dispatch(action)commit('mutation')dispatch('action')
是否支持异步操作不直接支持,需要结合其他工具(如 useEffect支持异步操作(通过 actions
模块化需要手动组织代码结构提供模块化支持(modules
学习曲线较低,适合小型到中型应用较高,适合中大型应用
import React, { useReducer } from 'react';// 初始状态
const initialState = { email: '', password: '' };//初始值由 initialState 定义:{ email: '', password: '' }。// Reducer 函数
// 它接收一个 action 对象(通常包含 type 和可选的 payload),并将这个 action 传递给 reducer。
// reducer 根据 action.type 和 action.payload 计算并返回新的状态。
const reducer = (state, action) => {switch (action.type) {case 'SET_EMAIL':return {...state,email: action.payload,};case 'SET_PASS':return {...state,password: action.payload,};default:return state;}
};function LoginForm() {const [state, dispatch] = useReducer(reducer, initialState); // state 是当前的状态对象,在这里它是一个包含 email 和 password 的对象。//每次调用 dispatch 时,state 会根据 reducer函数 的逻辑更新为新的值。return (<form>{/* 绑定 email 输入框 */}<inputtype="email"value={state.email}onChange={(e) => {dispatch({ type: 'SET_EMAIL', payload: e.target.value });}}placeholder="Enter email"/>{/* 绑定 password 输入框 */}<inputtype="password"value={state.password}onChange={(e) => {dispatch({ type: 'SET_PASS', payload: e.target.value });}}placeholder="Enter password"/>{/* 显示当前状态 */}<p>Email: {state.email}</p><p>Password: {state.password}</p></form>);
}export default LoginForm;

useSyncExternalStore 很少用 将非react状态钩子存储到react中

副作用钩子 effect hooks

useEffect useLayoutEffect useInsertionEffect

const [count, setCount] = useState(0)useEffect(() => {document.title = `You clicked ${count} times`
},[count])
//给 useEffect  提供一个运行函数  传入依赖项数组 依赖项数组变化时函数运行<button onClick={() => setCount(count + 1)}>Click Me</button>

副作用函数一般有两种 比如事件驱动副作用 点击按钮等事件 第二种 渲染驱动副作用 页面渲染后运行 调取接口

const ref = useRef(null)useEffect(() => {if(isPlaying){ref.current.play()}else{ref.current.pause()}
},[isPlaying])<video ref={ref} src={src} loop playsInline />

useLayoutEffect react 绘制后运行

useEffect 异步执行 钩子不会阻塞浏览器绘制(paint),这意味着它会在浏览器完成渲染后异步执行。这是最常用的副

作用钩子,适用于大多数情况,比如数据获取、订阅或者手动DOM更新等。

useLayoutEffect 会在所有的 DOM 变更之后同步执行。这可以保证在任何浏览器绘制之前,所有的 DOM 操作已经完成。因此,如果

你的副作用涉及到 DOM 操作,并且这些操作会影响到页面的布局或视觉效果,你应该使用 useLayoutEffect 来避免闪烁或其他视觉问

题。

const ref = useRef(null)
const [tooltipHeight, setTooltipHeight] = useState(0)useLayoutEffect(() => {const {height} = ref.current.getBoundingClientRect()setTooltipHeight(height)
},[])

useInsertionEffect 在渲染过程中插入样式 它可以让你在组件渲染之前插入样式定义,从而避免样式闪烁或未定义样式的问题。很少使

引用钩子 Ref hooks

useRef useImperativeHandle

useRef 访问dom实例 ref.current

const [timer, setTimer] = useState(0);
const intervalRef = useRef();
//启动计时器函数
const startTimer = () => {intervalRef.current = setInterval(() => {setTimer((prevTimer) => prevTimer + 1);}, 1000);
};
//startTimer 函数通过 setInterval 每隔 1 秒调用一次回调函数,该回调函数将 timer 状态增加 1。
//intervalRef.current 存储了 setInterval 返回的定时器 ID,以便稍后可以停止计时器。
// 停止计时器
const stopTimer = () => {clearInterval(intervalRef.current);
};<p>Timer: {timer} seconds</p>
<button onClick={startTimer}>Start Timer</button>
<button onClick={stopTimer}>Stop Timer</button>

useImperativeHandle 也是一种引用钩子 很少使用 当你需要在父组件中操作子组件的某些功能,但又不希望暴露整个子组件实例时。

父组件获取子组件输入框的焦点

父组件

import React, { useRef } from 'react';
import ChildComponent from './ChildComponent';function ParentComponent() {const childRef = useRef();const handleFocus = () => {childRef.current.focusInput();};const handleClear = () => {childRef.current.clearInput();};return (<div><ChildComponent ref={childRef} /><button onClick={handleFocus}>Focus Input</button><button onClick={handleClear}>Clear Input</button></div>);
}export default ParentComponent;

子组件

import React, { useRef, useImperativeHandle, forwardRef } from 'react';const ChildComponent = forwardRef((props, ref) => {const inputRef = useRef();// 自定义暴露的方法useImperativeHandle(ref, () => ({focusInput: () => {inputRef.current.focus();},clearInput: () => {inputRef.current.value = '';},}));return <input type="text" ref={inputRef} placeholder="Enter text" />;
});export default ChildComponent;

useImperativeHandle 定义了两个方法:

  • focusInput:让输入框获得焦点。

  • clearInput:清空输入框的内容。

  • 父组件只能调用这两个方法,而不能直接访问 inputRef 或其他内容。

  • useImperativeHandle 必须与 forwardRef 配合使用,因为只有 forwardRef 才能将 ref 传递到子组件。

上下文钩子

useContext

读取上下文值

//1 创建context
const AppContext = createContext()
//2 用Provider组件包裹
<AppContext.Provider value="你好"><App></App>      
</AppContext.Provider>
//3 useContext 获取值
function Title(){const text = useContext(AppContext)return <h1>{text}</h1>
}
其他钩子

useDebugValue useId

useDebugValue devtool调试用 很少使用

useId 创建唯一id 但不能用作key

function Form() {return (<form><EmailInput name="Email" /><EmailInput name="Confirm Email" /></form>);
}function EmailInput({ name }) {const id = useId();return (<><label htmlFor={id}>{name}</label><input id={id} type="email" /></>);
}
过渡钩子 处理过渡效果

useTransition

useDeferredValue

useTransition 指定状态更新 不紧急

const [filter, setFilter] = useState('');
const [inputValue, setInputValue] = useState('');
const [isPending, startTransition] = useTransition();const filteredItems = items.filter(item => item.includes(filter));<inputvalue={inputValue}onChange={(event) => {setInputValue(event.target.value);startTransition(() => {setFilter(event.target.value);});}}placeholder="Type to filter..."
/>
{isPending ? <p>Loading...</p> : filteredItems.map(item => <div key={item}>{item}</div>)}

useDeferredValue 延迟状态更新

性能优化钩子 performance hooks

useMemo useCallback

useMemo 提升性能 useMemo必须返回一个值

  • useMemo 是一个 React Hook,用于缓存计算结果,避免在每次渲染时都重新计算。
function SumComponent({ numbers }) {const sum = useMemo(() => {return numbers.reduce((total, n) => total + n, 0);}, [numbers]);return <h1>Sum: {sum}</h1>;
}
//接收一个数字数组 numbers 作为 props,并计算这些数字的总和。通过使用 useMemo,确保了只有在 numbers 发生变化时才重新计算总
//和,从而提高了组件的性能,避免了不必要的重复计算。
import React, { useMemo } from 'react';function SumComponent({ numbers }) {// 使用 useMemo 缓存计算结果const sum = useMemo(() => {console.log('Calculating sum...');return numbers.reduce((total, num) => total + num, 0);}, [numbers]); // 只有当 numbers 发生变化时才重新计算return (<div><h1>Sum: {sum}</h1></div>);
}export default function App() {const [numbers, setNumbers] = React.useState([1, 2, 3, 4, 5]);const [count, setCount] = React.useState(0);// 添加一个随机数到数组中const addRandomNumber = () => {setNumbers([...numbers, Math.floor(Math.random() * 100)]);};return (<div><h2>Current Count: {count}</h2><button onClick={() => setCount(count + 1)}>Increase Count</button><button onClick={addRandomNumber}>Add Random Number</button><SumComponent numbers={numbers} /></div>);
}

useCallback 缓存回调函数

function Counter() {const [count, setCount] = useState(0);const increment = useCallback(() => {setCount((c) => c + 1);}, []);return (<><div>{count}</div><Button onClick={increment} /></>);
}function Button({ onClick }) {return <button onClick={onClick}>Click me</button>;
}
React 19 新钩子

useFormStatus useFormState useOptimistic use

相关文章:

  • WordPress AI 原创文章自动生成插件 24小时全自动生成SEO原创文章 | 多语言支持 | 智能配图与排版
  • Docker安装(Ubuntu22版)
  • 【Java学习日记26】:方法的重载
  • yum包管理器
  • 面试中被问到mybatis与jdbc有什么区别怎么办
  • aws(学习笔记第三十九课) iot-msk-pipeline
  • 设备接入与APP(应用程序)接入华为云iotDA平台的路径元素有哪些不同?
  • ThreadLocal详解与实战指南
  • 深入浅出Sentinel:分布式系统的流量防卫兵
  • 【uniapp】vue2 搜索文字高亮显示
  • MongoDB Shard Cluster
  • 科技赋能建筑新未来:中建海龙模块化建筑产品入选中国建筑首批产业化推广产品
  • Kafka和flume整合
  • HOW - 如何模拟实现 gpt 展示答案的交互效果
  • Python判断语句-语法:if,if else,if elif else,嵌套,if else语句扁平式写法,案例
  • android jatpack Compose 多数据源依赖处理:从状态管理到精准更新的架构设计
  • kafka整合flume与DStream转换
  • #苍穹外卖# day 10-11
  • Move Registry 发布,实现 Sui 的超级互操作性
  • ubuntu22.04部署Snipe-IT
  • 居民被脱落的外墙瓦砖砸中致十级伤残,小区物业赔付16万元
  • 人民日报任仲平:为什么中国意味着确定性、未来性、机遇性
  • 面对面倾听群众意见建议,及时回应解决群众“急难愁盼”问题!龚正在基层开展下访活动,调研城市更新
  • 四川省人大常委会原党组成员、副主任宋朝华接受审查调查
  • 王旭任甘肃省副省长
  • 第四届全民阅读大会在太原举办,李书磊出席并讲话