React18入门(第三篇)——React Hooks详解,React内置Hooks、自定义Hooks使用

文章目录

    • 概述
    • 一、内置 Hook——useState
        • 1.1 响应式数据更新
        • 1.2 什么是 state
        • 1.3 state 特点(一)——异步更新
        • 1.4 state 特点(二)——可能会被合并
        • 1.5 state 特点(三)——不可变数据(重要!!!)
        • 1.6 使用 immer 修改 state
    • 二、内置 Hook——useEffect
        • 2.1 作用及使用
        • 2.2 执行时机
        • 2.3 useEffect 执行两次
    • 三、其他内置 Hooks
        • 3.1 useRef —— 用于Dom节点,用于JS变量
        • 3.2 useMemo —— 缓存变量
        • 3.3 useCallback—— 缓存函数
    • 四、自定义 Hook
        • 4.1 React Hooks 的正确打开方式
        • 4.2 React 组件公共逻辑的抽离和复用
        • 4.3 自定义 Hook —— 修改网页标题
    • 五、第三方 Hooks
        • 5.1 常见的第三方 Hooks
        • 5.2 ahooks 的使用
    • 六、Hooks 使用规则

概述

React Hooks 可以说是 React 最重要 的内容之一。常见的 React Hooks 命名 通常 以 use 开头,比如 useState、useEffect 等。
本文将采用图文详解的方式,带你快速了解:React 内置 Hooks、自定义 Hooks(复用代码)、第三方 Hooks 的使用。


一、内置 Hook——useState

1.1 响应式数据更新
import React, { useState } from 'react'function App() {// let count = 0  // 普通的 js 变量,无法触发组件的更新const [count, setCount] = useState(0) // useState 可以触发组件的更新function add() {setCount(count + 1)console.log(count, 'count')}return (<><div><button onClick={add}>add {count}</button></div></>)
}
export default App
1.2 什么是 state
  • props 是父组件传递过来的信息
  • state 是组件内部的状态信息,不对外
  • state 变化,触发组件更新,重新渲染 rerender 页面
1.3 state 特点(一)——异步更新
  • 写一个简单的累加方法,打印出来的 count 永远是累加之前的 count 。并非是同步更新
import React, { FC, useState } from 'react'const StateDemo: FC = () => {const [count, setCount] = useState(0) // useState 可以触发组件的更新const [name, setName] = useState('张三')function add() {// 写法一:setCount(count + 1)// 写法二:// setCount(count => count + 1)/** 打印出来的 count 永远是累加之前的 count */console.log(count, 'cur count') // 异步更新,无法直接拿到最新的 state 值 }return (<><button onClick={add}>add {count}</button></>)
}
export default StateDemo
  • 如果说一个变量不用于 JSX 中显示,那就不要用 setState 来管理它,用 useRef
import React, { FC, useState } from 'react'const StateDemo: FC = () => {const [name, setName] = useState('张三')function add() {setName('李四')console.log(name) // 如果说一个变量不用于 JSX 中显示,那就不要用 setState 来管理它,用 useRef}
}
export default StateDemo
1.4 state 特点(二)——可能会被合并
import React, { FC, useState } from 'react'const StateDemo: FC = () => {const [count, setCount] = useState(0) // useState 可以触发组件的更新function add() {/** 方法一:看代码觉得可能会实现 count + 5,但由于是异步更新,每次执行的时候,count 任然是0。所以最后仍然是 count + 1 */setCount(count + 1)setCount(count + 1)setCount(count + 1)setCount(count + 1)setCount(count + 1)/** 方法二:可以实现 count + 5 */setCount(count => count + 1)setCount(count => count + 1)setCount(count => count + 1)setCount(count => count + 1)setCount(count => count + 1)console.log(count, 'cur count')}return (<><div><button onClick={add}>add {count}</button></div></>)
}
export default StateDemo
1.5 state 特点(三)——不可变数据(重要!!!)

注:编辑 state 的数据只能是传入一个的数据进行覆盖,而不能修改原数据

import React, { FC, useState } from 'react'
import QuestionCard from './components/QuestionCard'const List2: FC = () => {// 问卷列表数据const [questionList, setQuestionList] = useState([{ id: 'q1', title: '问卷1', isPublished: false },{ id: 'q2', title: '问卷2', isPublished: true },{ id: 'q3', title: '问卷3', isPublished: true },{ id: 'q4', title: '问卷4', isPublished: false },])// 新增问卷function handleAdd() {// 生成三位随机数const r = Math.random().toString().slice(-3)setQuestionList(questionList.concat({id: 'q' + r,title: '问卷' + r,isPublished: false,}))}// 删除问卷function deleteQuestion(id: string) {setQuestionList(questionList.filter(item => item.id != id))}// 编辑问卷function publishedQuestion(id: string) {setQuestionList(questionList.map(item => {if (item.id !== id) return itemreturn {...item,isPublished: true,}}))}
}
export default List2
1.6 使用 immer 修改 state
  • state 是不可变数据
  • state 操作成本高,有很大不稳定性
  • 使用 immer 可避免这一个问题

安装 immer

npm install immer --save

使用 immer

import React, { FC, useState } from 'react'
import { produce } from 'immer'const Demo: FC = () => {const [userInfo, setUserInfo] = useState({ name: '张三', age: 24 })// 修改个人信息const handleChangeUser = () => {setUserInfo(// 通过 immer,即可让我们便捷的修改数据produce(draft => {draft.name = '李四'}))}return (<div><div>{JSON.stringify(userInfo)}</div><button onClick={handleChangeUser}>change age</button></div>)
}
export default Demo

二、内置 Hook——useEffect

2.1 作用及使用
import React, { FC, useState, useEffect } from 'react'
import { produce } from 'immer'
import QuestionCard from './components/QuestionCard'const List2: FC = () => {/** 方式一:直接发起 Ajax 请求。不行,state值改变时会触发请求,造成重复发送冗余请求 */// console.log('方式一加载 Ajax 网络请求')/** 方式二:此方法即可 */useEffect(() => {console.log('方式二加载 Ajax 网络请求')}, []) // 第二个参数为依赖项, 数组中可以放多个 state 值,当 state 值改变时,会触发 函数(第一个参数)的执行。若为空,const [questionList, setQuestionList] = useState([{ id: 'q1', title: '问卷1', isPublished: false },{ id: 'q2', title: '问卷2', isPublished: true },{ id: 'q3', title: '问卷3', isPublished: true },{ id: 'q4', title: '问卷4', isPublished: false },])
}
export default List2
2.2 执行时机

组件创建、销毁以及依赖的 state 数据改变时,会执行

import React, { FC, useState, useEffect } from 'react'
import { produce } from 'immer'
import QuestionCard from './components/QuestionCard'const List2: FC = () => {/** 方式一:直接发起 Ajax 请求。不行,会频繁的重复请求 */// console.log('方式一加载 Ajax 网络请求')/** 方式二:此方法即可 */useEffect(() => {// 组件挂载时执行console.log('component mounted')return () => {// 组件销毁时执行console.log('component unmounted')}}, [questionList]) // 如果此数组中依赖数据,则依赖数据更新时会执行const [questionList, setQuestionList] = useState([{ id: 'q1', title: '问卷1', isPublished: false },{ id: 'q2', title: '问卷2', isPublished: true },])
}
export default List2
2.3 useEffect 执行两次
  • React18 开始,useEffect 在开发环境下会执行两次
  • 目的是模拟左键创建、销毁、再创建的完整流程、及早暴露问题
  • 生产环境下会执行一次

三、其他内置 Hooks

3.1 useRef —— 用于Dom节点,用于JS变量
  • 一般用于操作 DOM
  • 也可以传入普通的 JS 变量,但更新不会触发 rerender
  • 要和 Vue3 ref 区分开(如果你用过 Vue3)

示例代码一:操作 DOM

import React, { FC, useRef } from 'react'const UseRefDemo: FC = () => {const inputRef = useRef<HTMLInputElement>(null)function handelSelect() {const element = inputRef.current  // 可以拿到 DOM 节点,进行 DOM 操作element?.select()}return (<div><input ref={inputRef} defaultValue="Hello Word" /><button onClick={handelSelect}>select button</button></div>)
}
export default UseRefDemo

示例代码二:不会触发 rerender

import React, { FC, useRef } from 'react'const UseRefDemo: FC = () => {const name = useRef('张三')function handleChangeName() {name.current = '王小虎' // 修改 ref 的值,不会触发 rerender(修改 state 的值,会触发 rerender)console.log(name.current, 'now name') // 此时页面仍然是 张三,但是此处打印出来的是 王小虎}return (<div><div>{name.current}</div><button onClick={handleChangeName}>select button</button></div>)
}
export default UseRefDemo
3.2 useMemo —— 缓存变量
  • 函数组件,每次 state 更新都会重新执行函数
  • useMemo 可以缓存数据,不用每次执行函数都重新生成
  • 可用于计算量较大的场景,缓存提高性能

使用示例代码:

import React, { FC, useMemo, useState } from 'react'const Demo: FC = () => {const [num1, setNum1] = useState(10)const [num2, setNum2] = useState(20)const [test, setTest] = useState('测试')  // 更新组件,导致组件 rerenderconst sum = useMemo(() => {return num1 + num2}, [num1, num2])return (<><p> {sum} </p><p> {num1}{' '}<button onClick={() => { setNum1(num1 + 1) }}>add num1</button></p><p> {num2}{' '} <button onClick={() => {setNum2(num2 + 2)}}>add num2</button></p><div>{/* form组件,受控组件 */}<input value={test} onChange={e => setTest(e.target.value)} /></div></>)
}
export default Demo
3.3 useCallback—— 缓存函数
  • 和 useMemo 作用类似
  • 专门用于 **缓存函数 **
  • 使用时根据业务而定,不能为了优化二优化
import React, { FC, useState, useCallback } from 'react'const Demo: FC = () => {const [text, setText] = useState('Hello')// fn1 是只要组件重新更新、重新执行,那么 fn1 就会被重新定义 -- 无缓存const fn1 = () => console.log('执行 fn1 ')// fn2 用了 useCallback ,就会根据依赖项去重新定义 -- 有缓存const fn2 = useCallback(() => {console.log('执行 fn2')}, [text]) // 依赖项,与 useEffect,useMemo,useCallback 用法类似// 缓存,为了性能优化,提升时间效率// 但是不能为了优化,要根据业务而定return (<><div><button onClick={fn1}>fn 1</button> &nbsp; <button onClick={fn2}>fn 2</button></div>{/* form组件,受控组件 */}<input value={text} onChange={e => setText(e.target.value)} /></>)
}
export default Demo

四、自定义 Hook

4.1 React Hooks 的正确打开方式
  • 内置 Hooks 保证基础功能
  • 内置 Hooks 灵活配合,实现业务功能
  • 抽离功能部分,自定义 Hooks 或者第三方 Hooks —— 复用嗲马
4.2 React 组件公共逻辑的抽离和复用
  • 之前是 class 组件,现在是函数组件
  • class 组件:Mixin(混合)、 HOC(高阶组件)、 render-props(渲染属性) 来复用公共逻辑
  • 函数组件:使用 Hooks —— 当前最完美的解决方案,Vue3也在参考
4.3 自定义 Hook —— 修改网页标题

4.3.1 定一个 hooks

// /src/hooks/useTitle.ts
import { useEffect } from 'react'function useTitle(title: string) {useEffect(() => {// 修改网页标题document.title = title}, [])
}
export default useTitle

4.3.2 使用 自定义 hooks

import React from 'react'
// 引入 自定的 hooks
import useTitle from './hooks/useTitle'function App() {... 其他代码// 使用自定义的 hooksuseTitle('React 自定义 Hook 学习')... 其他代码
}
export default App

4.3.3 页面效果
在这里插入图片描述


五、第三方 Hooks

5.1 常见的第三方 Hooks
  • ahooks – 国内常用 官网地址:https://ahooks.js.org/
  • react-use – 国外常用
5.2 ahooks 的使用

安装 ahooks

npm install --save ahooks

使用

import React from 'react';
import { useTitle } from 'ahooks';export default () => {useTitle('Page Title');return (<div><p>Set title of the page.</p></div>);
};

六、Hooks 使用规则

  • 必须用 useXxx 格式来命名
  • 只能在两个地方调用 Hook (*组件内、其他 Hook 内 *)
  • 必须保证每次调用顺序一致(不能将 Hook 放在 if for 内部)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/103272.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

非肿瘤纯生信拿下7+,多种机器学习算法,搭配WGCNA。

今天给同学们分享一篇非肿瘤WGCNA机器学习的生信文章“Screening of immune-related secretory proteins linking chronic kidney disease with calcific aortic valve disease based on comprehensive bioinformatics analysis and machine learning”&#xff0c;这篇文章于2…

PG14归档失败解决办法archiver failed on wal_lsn

问题描述 昨晚RepmgrPG14主备主库因wal日志撑爆磁盘&#xff0c;删除主库过期wal文件重做备库后上午进行主备状态巡查&#xff0c;主库向备库发送wal文件正常&#xff0c;但是查主库状态时发现显示有1条归档失败的记录。 postgres: archiver failed on 000000010000006F000000…

【算法-动态规划】零钱兑换问题-力扣 322

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

[ubuntu]OpenFOAM国内源码满速下载地址

下列地址可直接使用git clone&#xff0c;例如&#xff0c;打开终端&#xff0c;在终端直接将下面的复制进去&#xff1a; git clone https://e.coding.net/dyfluid/ThirdParty-6/ThirdParty-6.git即可在本地创建ThirdParty-6文件夹。如果提示你没有git&#xff0c;那么输入下面…

linux安装mysql

一、Mysql概述 MySQL 是一个开放源码的小型关联式数据库管理系统&#xff0c;开发者为瑞典 MySQL AB 公司。目前 MySQL 被广泛地应用在 Internet 上的中小型网站中。由于其体积小、速度快、总体拥有成本低&#xff0c;尤其是开放源码这一特点&#xff0c;许多中小型网站为了降…

看一下链表结构

序、慢慢来才是最快的方法。 背景 链表(Linked List) 链表是一种常见的基础数据结构&#xff0c;是一种线性表。与顺序表不同的是&#xff0c;链表中的每个节点不是顺序存储的&#xff0c;而是通过节点的指针域指向到下一个节点。 1.链表的优缺点 2.链表的类型 单链表、双链表…

有了PMP证书,还用考CSPM吗?

首先结论放前面&#xff08;看个人发展要求&#xff0c;如果想有双证加持的话&#xff0c;建议可以把握这个机会去申请&#xff0c;因为现在处于政策前期&#xff0c;可以免试申请&#xff0c;未来的政策未知。如果目前已经从事项目管理且拥有pmp证书的话&#xff0c;为了以后的…

将C盘中的文件夹迁移到其他盘符

目录 1 微信文件 2 移动系统自带文件夹 3 清除软件的缓存 1 微信文件 微信文件默认存储在C盘中&#xff0c;放任不管可能会占用很大的空间 更改后文件会自动挪过去&#xff0c;在C盘中只保留较小的空间 2 移动系统自带文件夹 像文档&#xff0c;图片这种文件夹&#…

TOGAF(企业架构)

TOGAF 核心概念&#xff08;官方原版&#xff09; 什么是TOGAF&#xff1f; TOGAF?是一种经验证的企业架构方法和框架&#xff0c;被世界领先的组织用于提高业务效率。它是一个企业架构标准&#xff0c;确保企业架构专业人员之间的标准、方法和通信一致&#xff0c;以便我们…

解读提示工程(Prompt Engineering)

提示工程&#xff08;Prompt Engineering&#xff09;&#xff0c;也称为上下文提示&#xff0c;是一种通过不更新模型的权重/参数来引导LLM行为朝着特定结果的方法。这是与AI有效交流所需结果的过程。提示工程可以用于各种任务&#xff0c;从回答问题到算术推理乃至各种应用领…

1808_ChibiOS基本的架构介绍

全部学习汇总&#xff1a; GreyZhang/g_ChibiOS: I found a new RTOS called ChibiOS and it seems interesting! (github.com) 简单看了一下ChibiOS的架构介绍&#xff0c;感觉这种OS以及组件非常适合快速构建一个应用。这里做一个简单的资料整理。。 1. 不同于其他的OS&#…

孙哥Netty视频笔记总结

视频在这儿&#xff1a;https://blog.csdn.net/weixin_43996338/article/details/133771464 【视频来源于&#xff1a;B站up主孙帅suns Spring源码视频】【微信号&#xff1a;suns45】 【更多面试资料请加微信号&#xff1a;suns45】 https://flowus.cn/share/f6cd2cbe-627a-43…

微信小程序 js中写一个px单位转rpx单位的函数

大家写东西自然还是会比较喜欢用rpx 但是 事实证明 在js中 还是px好用 因为很多单位交互的函数还是只返回px单位的 理论上将 750 rpx 是整个屏幕的宽度 那么 我们可以这样写一个函数 pxToRpx(px) {//获取整个屏幕的宽度单位 pxlet screenWidth wx.getSystemInfoSync().scree…

Linux 回顾总结

学习前提&#xff08;环境搭建&#xff09;&#xff1a;RHCSA Linux环境搭建-CSDN博客 目录 一、shell 二、文件 三、用户和组管理 四、权限 五、软件 六、网络 七、磁盘 一、shell Linux的操作界面常称为Shell&#xff0c;Shell是操作系统提供给用户使用的界面&#xf…

土壤水分烘干法流程

土壤水分烘干法流程 叠小盒子装土 对折 得到一个正方形&#xff0c;裁掉多余的。然后将正方形按如下形式折 再次对折 然后再展开&#xff0c;对着折痕&#xff0c;竖立起盒子边缘 把上面的尖角翻下来 最后将多余的长条裁出一个盒子底部大小的小方块&#xff0c;放入盒子…

几种常见算法模式与场景应用

在计算机科学中&#xff0c;算法是解决问题的步骤和策略的集合。许多问题都可以通过使用算法解决&#xff0c;这些算法在解决问题的过程中会展现出一些共性和模式。以下是几种常见的算法模式以及它们在场景中的应用&#xff1a; 分治法 (Divide and Conquer) 分治法是一种将问题…

在Vue+Ts+Vite项目中如何配置别名指向不同的目录并引用

在VueTsVite项目中如何配置别名指向不同的目录并引用 vite.config.ts配置如下&#xff1a;tsconfig.json中需要配置baseUrl和paths,如下所示&#xff1a;项目中直接引入案例&#xff1a; vite.config.ts配置如下&#xff1a; import { defineConfig, AliasOptions } from vite…

绘制X-Bar-S和X-Bar-R图,监测过程,计算CPK过程能力指数

X-Bar-S图和X-Bar-R图是统计质量控制中常用的两种控制图&#xff0c;用于监测过程的稳定性和一致性。它们的主要区别在于如何计算和呈现数据的变化以及所关注的问题类型。 X-Bar-S图&#xff08;平均值与标准偏差图&#xff09;&#xff1a; X-Bar代表样本均值&#xff0c;S代表…

路由高级特性

项目拓扑与项目需求 项目需求 某企业网络使用ospf和isis作为IGP协议实现内部网络的互联互通&#xff0c;区域规划和IP规划如图所示&#xff0c;现在要求实现如下需求&#xff1a; LSW1和AR1使用vlan10互联&#xff0c;与AR2使用vlan20互联&#xff0c;LSW1与LSW2、3、4之间使…

spring boot RabbitMq基础教程

RabbitMq 由于RabbitMQ采用了AMQP协议&#xff0c;因此它具备跨语言的特性。任何语言只要遵循AMQP协议收发消息&#xff0c;都可以与RabbitMQ交互。并且RabbitMQ官方也提供了各种不同语言的客户端。 但是&#xff0c;RabbitMQ官方提供的Java客户端编码相对复杂&#xff0c;一般…