React?Hooks useReducer?逃避deps組件渲染次數(shù)增加陷阱
前言
在快樂使用 React Hooks 開發(fā)自定義 Hooks 過程中,使用了 useEffect,useReducer,useRef,useCallback 等官方提供的 Hooks,將一些通用邏輯抽離出來,提高代碼復(fù)用性。
但在組合使用 useEffect,useReducer,React.memo 時,發(fā)生了組件在狀態(tài)未發(fā)生變化時觸發(fā)渲染,因?yàn)榇藙幼靼l(fā)生在 mousemove 鼠標(biāo)移動時,所以組件不必要渲染次數(shù)非常多。
自定義 Hooks 簡單實(shí)現(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ù)原樣返回,但是組件仍然進(jìn)行了渲染。
提前阻止 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進(jìn)行淺比較,一種組件性能優(yōu)化方式useCallback(fn, deps)緩存函數(shù)useMemo(() => fn, deps)緩存昂貴變量- useState(initialState)惰性初始state
,initialState` 只會在組件初始渲染中起作用,后續(xù)渲染時會被
參考文獻(xiàn)
以上就是React Hooks 之 useReducer 逃避deps后增加組件渲染次數(shù)的陷阱的詳細(xì)內(nèi)容,更多關(guān)于React Hooks useReducer組件渲染的資料請關(guān)注腳本之家其它相關(guān)文章!
- React?的?useReducer?和?Redux?的區(qū)別及什么情況下應(yīng)該使用?useReducer
- 詳解React如何使用??useReducer???高階鉤子來管理狀態(tài)
- 一文帶你搞懂React中的useReducer
- React組件useReducer的講解與使用
- React useContext與useReducer函數(shù)組件使用
- React Hooks - useContetx和useReducer的使用實(shí)例詳解
- React超詳細(xì)分析useState與useReducer源碼
- React useReducer終極使用教程
- react中useReducer復(fù)雜狀態(tài)管理
相關(guān)文章
詳解react使用react-bootstrap當(dāng)輪子造車
本篇文章主要介紹了詳解react使用react-bootstrap當(dāng)輪子造車,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-08-08
一文詳解ReactNative狀態(tài)管理rematch使用
這篇文章主要為大家介紹了ReactNative狀態(tài)管理rematch使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
ReactNative踩坑之配置調(diào)試端口的解決方法
本篇文章主要介紹了ReactNative踩坑之配置調(diào)試端口的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07
關(guān)于React中setState同步或異步問題的理解
相信很多小伙伴們都一直在疑惑,setState 到底是同步還是異步。本文就詳細(xì)的介紹一下React中setState同步或異步問題,感興趣的可以了解一下2021-11-11
React?Native?中限制導(dǎo)入某些組件和模塊的方法
這篇文章主要介紹了React?Native?中限制導(dǎo)入某些組件和模塊的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-08-08

