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.rhkb.cn/news/159035.html

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

相关文章

MySQL的各种锁

1. MySQL有遇到过死锁的问题吗&#xff1f;你是如何解决的&#xff1f; 死锁&#xff0c;就是两个或两个以上的线程在执行过程中&#xff0c;去争夺同一个共享资源导致互相等待的现象&#xff0c;在没有外部干预的情况下&#xff0c;线程会一直处于阻塞状态&#xff0c;无法往下…

【RocketMQ系列二】通过docker部署单机RocketMQ

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

goland安装教程

安装版本&#xff1a; goland-2023.2.3.exe

spring boot+ vue位置信息大数据综合管理平台源码

spring boot vue位置信息大数据综合管理平台源码 UWB技术的人员定位系统源码 智慧工厂是产业升级的外在表现形式&#xff0c;利用物联网技术加强信息管理的新模式&#xff0c;人员定位管理通过物联网技术、位置信息大数据的综合处理应用&#xff0c;在智慧工厂人员管理方面具有…

git强制删除本地分支 git branch -D

git强制删除本地分支 git branch -D git删除本地分支_zhangphil的博客-CSDN博客git branch -d <分支名>可以通过: git branch 查看所有本地分支及其名字&#xff0c;然后删除特定分支。https://blog.csdn.net/zhangphil/article/details/82255002 使用git branch -d删除…

MacBook/MacOS如何更新到指定的版本

背景 现在是A版本&#xff0c;想要更新到B&#xff0c;而目前能最新更新到C。 是可以做到的&#xff0c;不一定更新就得更新到最新的。 只要下载好B之后更新即可。 方法 思路是下载好目标的版本后更新&#xff0c;这里可以下载&#xff1a; https://support.apple.com/zh-…

Arbitrum Stylus 的工作原理

理解 Arbitrum 如何协调 EVM 和 WASM 的共存是至关重要的。这不仅仅是拥有两个独立的引擎&#xff1b;这是一种增强两者优势的协同关系。 Arbitrum 的独特架构允许 EVM 和 WASM 之间进行无缝和同步的操作&#xff0c;这要归功于其统一的状态、跨 VM 调用和兼容的经济模型。 用…

uniapp小程序实现绘制内容,生成海报并保存截图(Painter和Canvas两种方式举例)

一、Painter方法 Painter插件传送门 1.下载资源包 2.将资源包的如下部分 3.使用页面引入组件 ui样式 <paintercustomStyle=margin-left: 40rpx; height: 1000rpx;palette="{{palette}}"bind:imgOK="onImgOK"/>data 中数据(绘制内容,替换区域) pai…

8.简易无线通信

预备知识 Zigbee无线通信&#xff0c;需要高频的载波来提供发射效率&#xff0c;Zigbee模块之间要可以正常的收发&#xff0c;接收模块必须把接收频率设置和发射模块的载波频率一致。Zigbee有27个载波可以进行通信&#xff0c;载波叫做信道&#xff08;无线通信的通道&#xf…

Umi + React + Ant Design Pro + TS 项目搭建

新建项目目录 mkdir 【项目名称】在对应目录 D:\react\demo 中&#xff0c;安装 Umi 脚手架&#xff1a; yarn create umi接下来&#xff0c;安装将要用到的相关依赖 umijs/plugins&#xff1a; npm i umijs/plugins -Dumijs/plugins 是 Umi 的官方插件集&#xff0c;包含了…

STM32单片机入门学习(六)-光敏传感器控制LED

光敏传感器模块和LED接线 LED负极接B12,正极接VCC 光敏传感模块一DO端接B13,GND接GND&#xff0c;VCC接VCC,AO不接。 如图&#xff1a; 主程序代码&#xff1a;main.c #include "stm32f10x.h" #include "Delay.h" //delay函数所在头文件 #include …

HTTPS 加密全过程

加密协议以前是SSL,现在都是TLS, 而证书现在大多数都是SSL证书 抓包流程: TCP三次握手过后, 客户端发送Client Hello 服务器相应Server Hello 服务器再次响应发送证书: 服务器再发送公钥:

凉鞋的 Godot 笔记 109. 专题一 小结

109. 专题一 小结 在这一篇&#xff0c;我们来对第一个专题做一个小的总结。 到目前为止&#xff0c;大家应该能够感受到此教程的基调。 内容的难度非常简单&#xff0c;接近于零基础的程度&#xff0c;不过通过这些零基础内容所介绍的通识内容其实是笔者好多年的时间一点点…

Servlet的部署与安全

1 Servlet 部署 Servlet规范关于各个东西该放在哪里有许多严格的规则。 1.1 WAR war文件代表Web归档(Web Archive)&#xff0c;war实际就是一个JAR&#xff0c;只不过扩展名是.war而不是.jar。 其采用了一种可移植的压缩形式&#xff0c;把整个Web应用结构&#xff08;去掉…

go cpu、内存监控、性能分析:PProf

PProf PProf 是什么 PProf是 golang 官方提供的性能调优分析工具&#xff0c;用于分析和优化Go程序的性能。 PProf通过收集和分析程序的运行时数据来生成性能分析报告。它使用Go语言的运行时特性&#xff0c;如代码注释和特殊的程序运行标记&#xff0c;来收集性能数据。PPr…

【机器学习】sklearn对数据预处理

文章目录 数据处理步骤观察数据数据无量纲化缺失值处理处理分类型特征处理连续型特征 数据处理步骤 数据无量纲化缺失值处理处理分类型特征&#xff1a;编码与哑变量处理连续型特征&#xff1a;二值化与分段 观察数据 通过pandas读取数据&#xff0c;通过head和info方法大致查…

【ppt技巧】ppt里的图片如何提取出来?

之前分享过如何将PPT文件导出成图片&#xff0c;今天继续分享PPT技巧&#xff0c;如何提取出PPT文件里面的图片。 首先&#xff0c;我们将PPT文件的后缀名&#xff0c;修改为rar&#xff0c;将文件改为压缩包文件 然后我们将压缩包文件进行解压 最好是以文件夹的形式解压出来…

数据结构与算法(三)

文章目录 数据结构与算法(三)9 链表及其相关面试题9.1 链表查找9.2 给定一个单链表的头节点head,请判断该链表是否为回文结构9.3 链表的分区9.4 链表的复制10 链表相关面试题(续)、二叉树的常见遍历10.1 判断链表相交10.2 链表删除10.3 二叉树先序、中序、后序的递归遍历和…

C++笔记之std::future的用法

C笔记之std::future的用法 code review! 文章目录 C笔记之std::future的用法1.C中std::future和std::async总是一起出现吗&#xff1f;2.主要特点和用法3.一个完整的例子4.std::future 存放的是一个结果吗&#xff1f;5.cppreference——std::future 1.C中std::future和std::a…

3D 生成重建007-Fantasia3D和Magic3d两阶段玩转文生3D

3D生成重建3D 生成重建007-Fantasia3D和magic3d 文章目录 0 论文工作1 论文方法1.1 magic3d1.2 Fantasia3D 2 效果2.1 magic3d2.2 fantasia3d 0 论文工作 两篇论文都是两阶段法进行文生3d&#xff0c;其中fantasia3D主要对形状和外表进行解耦&#xff0c;然后先对geometry进行…