文章目錄
- 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].