網(wǎng)站首頁 編程語言 正文
前言
在快樂使用 React Hooks
開發(fā)自定義 Hooks
過程中,使用了 useEffect
,useReducer
,useRef
,useCallback
等官方提供的 Hooks
,將一些通用邏輯抽離出來,提高代碼復(fù)用性。
但在組合使用 useEffect
,useReducer
,React.memo
時,發(fā)生了組件在狀態(tài)未發(fā)生變化時觸發(fā)渲染,因為此動作發(fā)生在 mousemove
鼠標(biāo)移動時,所以組件不必要渲染次數(shù)非常多。
自定義 Hooks 簡單實現(xiàn)
import { useReducer } from "react"; const reducer = (state, action) => { const { sliding, lastPos, ratio } = state; switch (action.type) { case "start": return { ...state, slideRange: action.slideRange, lastPos: action.x, sliding: true, }; case "move": if (!sliding) { return state; } const offsetX = action.x - lastPos; const newRatio = ratio + offsetX / state.slideRange; if (newRatio > 1 || newRatio < 0) { return state; } return { ...state, lastPos: action.x, ratio: newRatio, }; case "end": if (!sliding) { return state; } return { ...state, sliding: false, }; case "updateRatio": return { ...state, ratio: action.ratio, }; default: return state; } }; export function useSlider(initialState) { const [state, dispatch] = useReducer(reducer, initialState); return [state, dispatch]; }
在組件中使用自定義 Hooks
const [state, dispatch] = useSlider(initialState); const { ratio, sliding, lastPos, slideRange } = state; useEffect(() => { const onSliding = (e) => { dispatch({ type: "move", x: e.pageX }); }; const onSlideEnd = () => { dispatch({ type: "end" }); }; document.addEventListener("mousemove", onSliding); document.addEventListener("mouseup", onSlideEnd); return () => { document.removeEventListener("mousemove", onSliding); document.removeEventListener("mouseup", onSlideEnd); }; }, [dispatch]); const handleThumbMouseDown = useCallback( (event) => { const hotArea = hotAreaRef.current; dispatch({ type: "start", x: event.pageX, slideRange: hotArea.clientWidth, }); if (event.target.className !== "point") { dispatch({ type: "updateRatio", ratio: (event.pageX - 30) / hotArea.clientWidth, }); } }, [dispatch] );
鼠標(biāo)每次移動,都會觸發(fā) dispatch({ type: "move", x: e.pageX })
,在 reducer
函數(shù)中,當(dāng) !sliding
時,不修改 state 數(shù)據(jù)原樣返回,但是組件仍然進行了渲染。
提前阻止 dispatch 觸發(fā)
將 sliding
判斷移動到 useEffect
中,提前阻止 dispatch
觸發(fā),并將 sliding
設(shè)置到 useEffect(fn, deps)
deps 中,保證監(jiān)聽函數(shù)中能取到 sliding
最新值。
useEffect(() => { const onSliding = (e) => { if(!sliding) { return; } dispatch({ type: "move", x: e.pageX }); }; const onSlideEnd = () => { if (!sliding) { return; } dispatch({ type: "end" }); }; document.addEventListener("mousemove", onSliding); document.addEventListener("mouseup", onSlideEnd); return () => { document.removeEventListener("mousemove", onSliding); document.removeEventListener("mouseup", onSlideEnd); }; }, [sliding]);
優(yōu)化后再測試
鼠標(biāo)僅移動時,sliding
為 false
,直接 return
,不會觸發(fā) dispatch
動作。
好處
避免了組件在 state
未修改時不必要渲染。
壞處
部分處理邏輯被移動到使用自定義 hooks
的組件中,sliding
數(shù)據(jù)改變時,add EventListener
函數(shù)會重新注冊。
結(jié)論
不能為了不在 useEffect(fn, deps)
設(shè)置 deps
,使用 useReducer
,并把所有數(shù)據(jù)變更都放在 reducer
中。 本篇文章通過把不修改 reducer
state
的動作提前阻止,避免使用此自定義 hooks 的組件發(fā)生不必要渲染,提高代碼復(fù)用性的同時也兼顧了組件性能。
題外
-
React.memo
對props
進行淺比較,一種組件性能優(yōu)化方式 -
useCallback(fn, deps)
緩存函數(shù) -
useMemo(() => fn, deps)
緩存昂貴變量 - useState(initialState)惰性初始state
,
initialState` 只會在組件初始渲染中起作用,后續(xù)渲染時會被
參考文獻
React 官方文檔
原文鏈接:https://juejin.cn/post/7139834444630163463
相關(guān)推薦
- 2023-06-21 Docker安裝部署Redis數(shù)據(jù)庫的實現(xiàn)步驟_docker
- 2022-11-14 Go語言文件讀寫操作案例詳解_Golang
- 2022-12-26 Python中pywifi模塊的基本用法講解_python
- 2022-02-24 Golang?strings包常用字符串操作函數(shù)_Golang
- 2022-04-30 Qt數(shù)據(jù)庫應(yīng)用之實現(xiàn)通用數(shù)據(jù)庫分頁_C 語言
- 2022-04-01 k8s 1.22 安裝ingress報錯the server could not find the
- 2022-08-19 Python運行時修改業(yè)務(wù)SQL代碼_python
- 2022-05-13 修復(fù)Qt程序長時間運行控件停止刷新
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支