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

React中hook的用法及例子(持续更新)

1、useCallback

作用是缓存函数

例子:父组件把一个函数 handleClick 传递给一个子组件。如果不使用 useCallback,即使 handleClick 没变,他也会在点击“切换Toggle”的时候重新渲染一遍(即打印:ChildButton: props 更新了)。

如果加上了useCallback,他就只会在依赖项count 改变的时候才重新渲染handleClick

import { useState, useCallback,useEffect } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'// 子组件:接收一个 onClick 函数
const ChildButton = ({ onClick }) => {useEffect(() => {console.log('✅ ChildButton: props 更新了')console.log('当前 onClick 函数引用:', onClick)}, [onClick]) // 🔥 依赖:只有当 onClick 引用变化时,这个 effect 才会执行return <button onClick={onClick}>我是子组件按钮</button>
}function App() {const [count, setCount] = useState(0)const [toggle, setToggle] = useState(true)// ❌ 每次渲染都会创建一个新函数(没有 useCallback)// const handleClick = () => {//   alert(`当前计数: ${count}`)// }// ✅ 使用 useCallback 缓存函数// 只有当 `count` 改变时,函数才会重新创建const handleClick = useCallback(() => {alert(`当前计数: ${count}`)}, [count]) // 依赖数组:只有 count 变化时才重新生成函数return (<><div className="app"><h1>useCallback 示例</h1><div><p>计数: {count}</p><button onClick={() => setCount(count + 1)}>增加计数</button></div><div style={{ margin: '20px 0' }}><p>Toggle 状态: {toggle ? 'ON' : 'OFF'}</p><button onClick={() => setToggle(!toggle)}>切换 Toggle</button></div><hr />{/* 子组件:接收缓存的函数 */}<ChildButton onClick={handleClick} /></div></>)
}export default App

2、useMemo

作用是缓存计算结果

例子:如果不使用useMemo,每次点击“切换Toggle”都会计算一遍slowSquare这个计算函数(即打印:正在进行昂贵的计算...)

使用useMemo后,只有count改变时候,才会计算slowSquare这个计算函数。

import { useState, useMemo } from 'react' // ✅ 导入 useMemo
import './App.css'// 一个非常耗时的计算函数(模拟复杂逻辑)
const slowSquare = (num) => {console.log('🔍 正在进行昂贵的计算...') // 我们靠它来“看到”是否重新计算了return num * num // 返回平方(但前面的循环让它变慢)
}function App() {const [count, setCount] = useState(0)const [toggle, setToggle] = useState(true)// ❌ 每次渲染都会重新执行 slowSquare(很慢!)// const expensiveValue = slowSquare(count)// ✅ 使用 useMemo 缓存计算结果const expensiveValue = useMemo(() => {return slowSquare(count)}, [count]) // 只有当 count 变化时,才重新计算return (<><div className="app"><h1>useMemo 示例</h1><div><p>计数: {count}</p><button onClick={() => setCount(count + 1)}>增加计数</button></div><div style={{ margin: '20px 0' }}><p>Toggle 状态: {toggle ? 'ON' : 'OFF'}</p><button onClick={() => setToggle(!toggle)}>切换 Toggle(无关状态)</button></div><hr />{/* 显示缓存的计算结果 */}<p><strong>{count}</strong> 的平方是:<span style={{ color: 'blue' }}> {expensiveValue} </span></p></div></>)
}export default App

3、React.memo

作用是缓存组件

例子:如果不使用React.memo包裹子组件,每次点击点击“切换 Toggle”时,都会重新渲染子组件(即打印:ExpensiveComponent 正在渲染!)

使用React.memo包裹子组件,只有count改变时候,才会重新渲染子组件

import React, { useState } from 'react'
import './App.css'// 子组件:模拟一个“昂贵”的组件(比如渲染大量 DOM)
const ExpensiveComponent = ({ count }) => {console.log('💥 ExpensiveComponent 正在渲染!')return (<div style={{ padding: '20px', border: '2px solid #007acc', borderRadius: '8px' }}><h3>我是昂贵的子组件</h3><p>我接收的 count 值是: <strong>{count}</strong></p></div>)
}// ✅ 使用 React.memo 包裹子组件
const MemoizedExpensiveComponent = React.memo(ExpensiveComponent)function App() {const [count, setCount] = useState(0)const [toggle, setToggle] = useState(true)return (<><div className="app" style={{ padding: '20px', fontFamily: 'Arial' }}><h1>React.memo 示例</h1><div><p>计数: {count}</p><button onClick={() => setCount(count + 1)}>增加计数(会触发子组件更新)</button></div><div style={{ margin: '30px 0' }}><p>Toggle 状态: {toggle ? 'ON' : 'OFF'}</p><button onClick={() => setToggle(!toggle)}>切换 Toggle(不会影响子组件 props)</button></div><hr />{/* 使用 memo 包裹后的组件 */}<MemoizedExpensiveComponent count={count} />{/* 没有使用 memo */}{/* <ExpensiveComponent count={count} /> */}</div></>)
}export default App

4、useContext

“跨层级”传递数据,无需prop

在React 内部维护了一个“上下文栈”,当组件调用 useContext 时,React 会:

  1. 检查当前渲染的“上下文环境”
  2. 找到对应 Context 的最新 value
  3. 建立“订阅关系”:Provider → useContext 组件

通俗解释:

  • ThemeContext = 一个广播电
  • <ThemeContext.Provider value={...}> = 电台正在播放节目
  • useContext(ThemeContext) = 你打开收音机,收听节目
  • 无论你在城市哪个角落(组件树多深),只要打开收音机,就能听到

同级创建几个组件:

父组件App.jsx

<ThemeContext.Provider>开始广播!

value={contextValue}:广播的内容是 { theme: 'dark', toggleTheme: function }

// src/App.jsx
import React, { useState } from 'react'
import ThemeContext from '.ThemeContext'
import ThemeToggle from './ThemeToggle'
import DeepComponent from './DeepComponent'function App() {const [theme, setTheme] = useState('light')const toggleTheme = () => {setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'))}// 提供给所有子组件的值const contextValue = { theme, toggleTheme }return (<ThemeContext.Provider value={contextValue}><divstyle={{padding: '20px',textAlign: 'center',minHeight: '100vh',background: theme === 'dark' ? '#121212' : '#fff',color: theme === 'dark' ? '#fff' : '#000',transition: 'background-color 0.3s, color 0.3s',}}><h1>useContext 主题切换示例(组件拆分)</h1><ThemeToggle /><p>当前主题: {theme}</p><hr style={{ margin: '40px 0' }} /><DeepComponent /></div></ThemeContext.Provider>)
}export default App

ThemeContext.jsx

创建“广播电台”,即创建了一个“上下文容器”

// src/context/ThemeContext.jsx
import { createContext } from 'react'// 创建一个 Context,可以设置默认值(可选)
const ThemeContext = createContext({theme: 'light', // 默认主题toggleTheme: () => {}, // 空函数作为默认
})export default ThemeContext

ThemeToggle.jsx

收听广播 + 操作广播

import React, { useContext } from 'react'
import ThemeContext from './ThemeContext'const ThemeToggle = () => {const { theme, toggleTheme } = useContext(ThemeContext)return (<buttononClick={toggleTheme}style={{padding: '10px 20px',fontSize: '16px',background: theme === 'dark' ? '#333' : '#f0f0f0',color: theme === 'dark' ? 'white' : 'black',border: '1px solid #ccc',borderRadius: '4px',cursor: 'pointer',}}>切换到 {theme === 'dark' ? '亮色' : '暗色'} 主题</button>)
}export default ThemeToggle

DeepComponent.jsx

收听广播 + 操作广播

import React, { useContext } from 'react'
import ThemeContext from './ThemeContext'const DeepComponent = () => {const { theme } = useContext(ThemeContext)return (<divstyle={{padding: '20px',margin: '20px 0',background: theme === 'dark' ? '#1a1a1a' : '#e0e0e0',color: theme === 'dark' ? 'white' : 'black',borderRadius: '8px',}}><h3>我是深层组件</h3><p>当前主题: {theme}</p></div>)
}export default DeepComponent

结果如下:


文章转载自:

http://XYNcdDcQ.xLqgs.cn
http://c4RUWNwQ.xLqgs.cn
http://B7YTNCqw.xLqgs.cn
http://u1X2McqJ.xLqgs.cn
http://IuCSe7wZ.xLqgs.cn
http://CtCnKwQi.xLqgs.cn
http://hEanOVbw.xLqgs.cn
http://EjummJwV.xLqgs.cn
http://EmfIwPjq.xLqgs.cn
http://RSLEJxYY.xLqgs.cn
http://MUmMIzlz.xLqgs.cn
http://uX97VqKR.xLqgs.cn
http://tB9y6hfb.xLqgs.cn
http://1O96MiLg.xLqgs.cn
http://rOnilZ8N.xLqgs.cn
http://TK00zZ3K.xLqgs.cn
http://l4YOYPFc.xLqgs.cn
http://hysyC3US.xLqgs.cn
http://EdYqpjxD.xLqgs.cn
http://hiDtvpus.xLqgs.cn
http://HpkyxOa7.xLqgs.cn
http://kClMU6nZ.xLqgs.cn
http://rr6pnE2S.xLqgs.cn
http://IxUfVfiK.xLqgs.cn
http://Ik6mVScf.xLqgs.cn
http://RxZ2iAwM.xLqgs.cn
http://yk8VIw70.xLqgs.cn
http://sazUcZkH.xLqgs.cn
http://IyZniIef.xLqgs.cn
http://xJtj60xZ.xLqgs.cn
http://www.dtcms.com/a/379094.html

相关文章:

  • 【网络编程】TCP、UDP、KCP、QUIC 全面解析
  • 【1】占位符
  • A2A 中的内存共享方法
  • 力扣704. 二分查找
  • HttpServletRequest vs ServletContext 全面解析
  • 介绍keepalived和LVS
  • NAT技术:SNAT与DNAT区别详解
  • 设计模式-单例桥接命令职责链
  • 数据分析:合并
  • bug:uniCloud报Business Failed, 参数有误retry invoke error
  • 人工智能学习:Transformer结构中的子层连接(Sublayer Connection)
  • 阿里FunASR语音转文字模型搭建
  • Android8 binder源码学习分析笔记(三)
  • sizeof 和 strlen
  • 2025年度4款录音转文字工具横向对比
  • 教资科三【信息技术】— 学科知识(简答题)精简背诵版
  • 滚动列表展示跟随弹框效果
  • readelf 和 ldd 查看文件的依赖
  • 基于社交媒体数据的公众情绪指数构建与重大事件影响分析
  • Cosign 实战:构建可信容器镜像的签名与验证体系
  • 定时器实战:LED闪烁与呼吸灯调试
  • docker部署Gitlab社区版,步骤以及外网访问出现502的解决方式
  • FairGuard aab包签名工具
  • 企业文件图纸全自动加密怎么设置?三步实现自动防护!
  • Redis C++ 实现笔记(I篇)
  • [css] 实现禁止文本被选中
  • MATLAB中进行视觉检测入门教程
  • 人工智能深度学习——多层感知器(人工神经网络)
  • 2025最新超详细FreeRTOS入门教程:第十二章 FreeRTOS调度器与时间片管理
  • 软考系统架构设计师之项目管理篇