文章目录
- 1. 副作用
- 2.其他内置hooks
- 2.1 useEffect
- 2.2 useRef
- 2.3useMemo
- 2.4 useCallback
- 3.自定义hooks
- 4. 第三方hooks
- 5. hooks使用原则
- 6. hooks闭包陷阱
- 7. 总结
- 结语
1. 副作用
- 当组件渲染完成时,加载一个Ajax网络请求
- 当某个state更新时,加载一个Ajax网络请求
示例:
const List2: FC = () => {console.log("加载Ajax网络请求。。。");...
控制台如下图所示:
分析:函数式组件,任何state更新,都会重新执行函数;组件初次渲染,也会执行函数。
解决这种情况,通过如下其他hooks完成。
2.其他内置hooks
2.1 useEffect
- useEffect用法
解决“当组件渲染完成时,加载一个Ajax网络请求”问题,如下所示:
useEffect(() => {console.log("渲染完成");}, []);
// 格式
useEffect(setup, dependencies?)
useEffect(func, [])
组件渲染完成,执行一次。
-
参数分析:
-
func:函数
-
[]:依赖于…触发,默认”空“当前组件。
-
-
useEffect执行只依赖于[]中指定的变量,可以是多个,任一一个变量更新,都触发函数执行。示例如下
useEffect(() => {console.log("渲染完成");}, []);useEffect(() => {console.log("questionList change");}, [questionList]);
- 执行组件增、改、删,打印questionList change
- 执行组件增、改、删,打印questionList change
-
组件销毁时触发useEffect,QuestionCard.tsx如下
useEffect(() => {console.log("QuestionCard mounted");return () => {console.log("QuestionCard unmounted " + id);};}, []);
- 控制台打印如下所示:
- 控制台打印如下所示:
-
useEffect监听react组件的声明周期:创建、更新、销毁等。
-
useEffect组件执行创建-销毁-在创建原因:从v18版本开始,在开发环境下会执行该过程;在生成环境中只执行一次。
yarn build 把打包好的文件放置在nginx配置的web路径下
- 如下图所示:
- 如下图所示:
2.2 useRef
在 React 开发中,开发者常常需要直接操作 DOM 元素或存储临时数据,但 React 的状态管理机制(如 useState
)有时无法满足这些需求。这时,一个名为 useRef
的 Hook 就像一位灵活的“中间人”,在虚拟 DOM 与真实 DOM 之间架起了一座桥梁。本文将深入探讨 useRef
的核心原理、使用场景及进阶技巧,帮助开发者高效利用这一工具解决实际问题。
- 什么是 useRef?
useRef
是 React 提供的一个 Hook,用于创建可变的引用(reference),其核心特性是:
- 不会触发组件重渲染:修改
useRef
的值不会导致组件重新渲染; - 直接访问 DOM 元素:通过
ref
属性绑定到 DOM 元素,获取其真实引用; - 存储临时数据:适合保存不需要触发 UI 更新的临时变量。
示例:
import { FC, useRef } from "react";const Demo: FC = () => {const inputRef = useRef<HTMLInputElement>(null);function selectInput() {const inputEle = inputRef.current;inputEle && inputEle.select();}return (<div><input ref={inputRef} defaultValue="hello world" /><button onClick={selectInput}> 点击选中</button></div>);
};export default Demo;
- 一般用于操作DOM
- 也可传入普通JS变量,单更新不会触发rerender
2.3useMemo
- 函数组件,每次state更新都会重新执行函数
- useMemo可以缓存数据,不用每次执行函数都重新生成
- 可用于计算量较大的场景,缓存提高性能
import { FC, useState, useMemo } from "react";
const Demo: FC = () => {console.log("demo...");const [num1, setNum1] = useState(10);const [num2, setNum2] = useState(20);const [text, setText] = useState("hello");const sum = useMemo(() => {console.log("sum use memo ");return num1 + num2;}, [num1, num2]);return (<><p>{sum} </p><p>{num1}<buttononClick={() => {setNum1(num1 + 1);}}>add num1</button></p><p>{num2}<buttononClick={() => {setNum2(num2 + 1);}}>add num2</button></p><div><input onChange={(e) => setText(e.target.value)} value={text} /></div></>);
};export default Demo;
2.4 useCallback
- 和useMemo作用一样,专门用于缓存函数
示例:
import { FC, useState, useCallback } from "react";const Demo: FC = () => {const [text, setText] = useState("hello");const fn1 = () => console.log("fn1 text ", text);const fn2 = useCallback(() => {console.log("fn2 text ", text);}, [text]);return (<><div><button onClick={fn1}>fn1</button><hr /><button onClick={fn2}>fn2</button></div><div><input onChange={(e) => setText(e.target.value)} value={text} /></div></>);
};export default Demo;
缓存,性能优化,提示时间效率。
3.自定义hooks
- 内置hooks保证基础的功能
- 内置hooks灵活配合,实现业务功能
- 抽离公共部分,自定义hooks或者第三方hooks-复用代码
代码演示1:修改网页标题
UseTitle.ts
import { useEffect } from "react";function useTitle(title: string) {useEffect(() => {document.title = title;}, []);
}export default useTitle;
App.tsx
import useTitle from "./hooks/UseTitle";function App() {useTitle("自定义标题1");return (<></>);
}export default App;
代码演示2:获取鼠标位置
useMouse.ts
import { useState, useEffect } from "react";// 获取鼠标位置,自定义hooks
function useMouse() {const [x, setX] = useState(0);const [y, setY] = useState(0);// 鼠标事件处理const mouseEventHandler = (e: MouseEvent) => {setX(e.clientX);setY(e.clientY);};useEffect(() => {// 监听鼠标事件window.addEventListener("mousemove", mouseEventHandler);//组件销毁时,一定要解绑DOM事件(不解绑,可能出现内存泄露问题)return () => {// 解绑鼠标事件,与绑定时参数相同window.removeEventListener("mousemove", mouseEventHandler);};}, []);return { x, y };
}export default useMouse;
App.tsx
import useMouse from "./hooks/useMouse";function App() {const { x, y } = useMouse();return (<><p>鼠标位置:{x} {y}</p></>);
}export default App;
效果如下图所示:
代码演示3:模拟异步获取数据
useGetInfo.ts
import { useState, useEffect } from "react";// 异步获取信息
function getInfo(): Promise<string> {return new Promise((resolve) => {setTimeout(() => {resolve(new Date().toString());}, 1500);});
}const useGetInfo = () => {const [loading, setLoading] = useState(true);const [info, setInfo] = useState("");useEffect(() => {getInfo().then((info) => {setLoading(false);setInfo(info);});}, []);return { loading, info };
};export default useGetInfo;
App.tsx
import useGetInfo from "./hooks/useGetInfo";function App() {const { loading, info } = useGetInfo();return (<><div>{loading ? "加载中" : info}</div></>);
}export default App;
效果如下图所示:
4. 第三方hooks
常用第三方hooks:文档地址参考下面链接2和链接3
- ahooks
- react-use
以ahooks为例,演示:修改网页标题
import { useTitle } from "ahooks";function App() {useTitle("自定义标题2");return (<></>);
}export default App;
演示:获取鼠标位置
import { useMouse } from "ahooks";function App() {const { clientX, clientY } = useMouse();return (<><p>鼠标位置:{clientX} {clientY}</p></>);
}export default App;
5. hooks使用原则
- 使用useXxx格式命名
- 只能在两个地方调用hook:组件内,其他hook内。
- 必须保证每次的调用顺序一致(不能放在if for内部)
6. hooks闭包陷阱
- 当异步函数获取state时,可能不是当前最新的state
- 可以使用useRef解决
演示示例:
Cloususe.tsx
import { FC, useState, useRef, useEffect } from "react";const Demo: FC = () => {const [count, setCount] = useState(0);// 累加function add() {setCount(count + 1);}// 打印countfunction printCount() {setTimeout(() => {console.log(count);}, 2000);}return (<><p>闭包陷阱</p><div><p>{count}</p><button onClick={add}>累加</button><button onClick={printCount}>打印</button></div></>);
};export default Demo;
App.tsx
import ClosureTrap from "./ClosureTrap";function App() {return (<><ClosureTrap /></>);
}export default App;
效果如下图所示:
解决方案:
Clousure.tsx
import { FC, useState, useRef, useEffect } from "react";const Demo: FC = () => {const [count, setCount] = useState(0);const countRef = useRef(0);useEffect(() => {countRef.current = count;}, [count]);// 累加function add() {setCount(count + 1);}// 打印countfunction printCount() {setTimeout(() => {console.log(countRef.current);}, 2000);}return (<><p>闭包陷阱</p><div><p>{count}</p><button onClick={add}>累加</button><button onClick={printCount}>打印</button></div></>);
};export default Demo;
效果如下图所示:
7. 总结
目标:
- 学会内置hooks
- 学会自定义hooks
- 学会使用第三方hooks
知识点:
-
自定义hooks
-
useState
- Immer:state的不可变数据
-
useEffect
-
useRef
-
useMemo
-
useCallback
-
-
第三方hooks
-
ahooks
-
react-use
-
-
闭包陷阱
注意事项:
- hooks是React最重要的内容之一
- 初学者很难通过概念理解hooks,必须配合大量实践练习
- hooks有很多规则,遇到错误时,先看是否违反规则
结语
❓QQ:806797785
⭐️仓库地址:https://gitee.com/gaogzhen
⭐️仓库地址:https://github.com/gaogzhen
[1]useEffect[CP/OL].
[2]ahook官网[CP/OL].
[3]github react-use[CP/OL].