學(xué)習(xí)內(nèi)容來源:React + React Hook + TS 最佳實(shí)踐-慕課網(wǎng)
相對原教程,我在學(xué)習(xí)開始時(shí)(2023.03)采用的是當(dāng)前最新版本:
項(xiàng) | 版本 |
---|---|
react & react-dom | ^18.2.0 |
react-router & react-router-dom | ^6.11.2 |
antd | ^4.24.8 |
@commitlint/cli & @commitlint/config-conventional | ^17.4.4 |
eslint-config-prettier | ^8.6.0 |
husky | ^8.0.3 |
lint-staged | ^13.1.2 |
prettier | 2.8.4 |
json-server | 0.17.2 |
craco-less | ^2.0.0 |
@craco/craco | ^7.1.0 |
qs | ^6.11.0 |
dayjs | ^1.11.7 |
react-helmet | ^6.1.0 |
@types/react-helmet | ^6.1.6 |
react-query | ^6.1.0 |
@welldone-software/why-did-you-render | ^7.0.1 |
@emotion/react & @emotion/styled | ^11.10.6 |
具體配置、操作和內(nèi)容會(huì)有差異,“坑”也會(huì)有所不同。。。
一、項(xiàng)目起航:項(xiàng)目初始化與配置
- 一、項(xiàng)目起航:項(xiàng)目初始化與配置
二、React 與 Hook 應(yīng)用:實(shí)現(xiàn)項(xiàng)目列表
- 二、React 與 Hook 應(yīng)用:實(shí)現(xiàn)項(xiàng)目列表
三、TS 應(yīng)用:JS神助攻 - 強(qiáng)類型
- 三、 TS 應(yīng)用:JS神助攻 - 強(qiáng)類型
四、JWT、用戶認(rèn)證與異步請求
- 四、 JWT、用戶認(rèn)證與異步請求(上)
- 四、 JWT、用戶認(rèn)證與異步請求(下)
五、CSS 其實(shí)很簡單 - 用 CSS-in-JS 添加樣式
- 五、CSS 其實(shí)很簡單 - 用 CSS-in-JS 添加樣式(上)
- 五、CSS 其實(shí)很簡單 - 用 CSS-in-JS 添加樣式(下)
六、用戶體驗(yàn)優(yōu)化 - 加載中和錯(cuò)誤狀態(tài)處理
- 六、用戶體驗(yàn)優(yōu)化 - 加載中和錯(cuò)誤狀態(tài)處理(上)
- 六、用戶體驗(yàn)優(yōu)化 - 加載中和錯(cuò)誤狀態(tài)處理(中)
- 六、用戶體驗(yàn)優(yōu)化 - 加載中和錯(cuò)誤狀態(tài)處理(下)
七、Hook,路由,與 URL 狀態(tài)管理
- 七、Hook,路由,與 URL 狀態(tài)管理(上)
- 七、Hook,路由,與 URL 狀態(tài)管理(中)
- 七、Hook,路由,與 URL 狀態(tài)管理(下)
八、用戶選擇器與項(xiàng)目編輯功能
- 八、用戶選擇器與項(xiàng)目編輯功能(上)
- 八、用戶選擇器與項(xiàng)目編輯功能(下)
九、深入React 狀態(tài)管理與Redux機(jī)制
1&2
- 九、深入React 狀態(tài)管理與Redux機(jī)制(一)
3.合并組件狀態(tài),實(shí)現(xiàn)useUndo
功能描述:
可以對一個(gè)數(shù)字進(jìn)行不斷地賦值,同時(shí)記錄下歷史值;可以通過undo對當(dāng)前值進(jìn)行撤銷操作,一步步地回到最初值。在進(jìn)行撤銷操作的同時(shí),記錄下undo掉的值;通過redo可以回到undo之前的值,不斷地redo最終可以回到執(zhí)行所有撤銷操作之前的值。
代碼實(shí)現(xiàn)
使用useState實(shí)現(xiàn)該hook,由于多個(gè)state值之前相互引用。因此useCallback的依賴項(xiàng)中會(huì)填入多個(gè)state作為依賴項(xiàng),但是在useCallback的回調(diào)函數(shù)中,在調(diào)用時(shí)會(huì)更新state值導(dǎo)致頁面重新渲染,useCallback的回調(diào)函數(shù)也被重新定義了。
接下來模仿實(shí)現(xiàn) use-undo
- use-undo-demo - CodeSandbox
- use-undo - npm
新建 src\utils\use-undo.ts
:
import { useState } from "react";
export const useUndo = <T>(initialPresent: T) => {
// 記錄歷史操作的合集
const [past, setPast] = useState<T[]>([])
const [present, setPresent] = useState(initialPresent)
// 記錄未來操作的合集
const [future, setFuture] = useState<T[]>([])
const canUndo = past.length !== 0
const canRedo = future.length !== 0
const undo = () => {
if (!canUndo) return
const previous = past[past.length - 1]
const newPast = past.slice(0, past.length - 1)
setPast(newPast)
setPresent(previous)
setFuture([present, ...future])
}
const redo = () => {
if (!canRedo) return
const next = future[0]
const newFuture = future.slice(1)
setFuture(newFuture)
setPresent(next)
setPast([...past, present])
}
const set = (newPresent: T) => {
if (newPresent === present) {
return
}
setPast([...past, present])
setPresent(newPresent)
setFuture([])
}
const reset = (newPresent: T) => {
setPast([])
setPresent(newPresent)
setFuture([])
}
return [
{past, present, future},
{redo, undo, set, reset, canRedo, canUndo}
] as const
}
現(xiàn)需要對代碼做以下優(yōu)化:
- 使用 useCallback 避免 造成之前的那種 依賴不等導(dǎo)致的循環(huán)渲染
- 將用到的 變量合并聲明 后續(xù)也同步改動(dòng)
- SetXXX 使用函數(shù)形式 直接使用歷史狀態(tài) 避免外界狀態(tài)的使用,減少依賴
import { useCallback, useState } from "react";
export const useUndo = <T>(initialPresent: T) => {
// 合并聲明
const [state, setState] = useState<{
past: T[],
present: T,
future: T[]
}>({
past: [],
present: initialPresent,
future: []
})
// 另一種寫法
// const [state, setState] = useState({
// past: [] as T[],
// present: initialPresent as T,
// future: [] as T[]
// })
const canUndo = state.past.length !== 0
const canRedo = state.future.length !== 0
const undo = useCallback(() => {
setState(currentState => {
const { past, present, future } = currentState
if (past.length === 0) return currentState
const previous = past[past.length - 1]
const newPast = past.slice(0, past.length - 1)
return {
past: newPast,
present: previous,
future: [present, ...future]
}
})
}, [])
const redo = useCallback(() => {
setState(currentState => {
const { past, present, future } = currentState
if (future.length === 0) return currentState
const next = future[0]
const newFuture = future.slice(1)
return {
past: [...past, present],
present: next,
future: newFuture
}
})
}, [])
const set = useCallback((newPresent: T) => {
setState(currentState => {
const { past, present } = currentState
if (newPresent === present) {
return currentState
}
return {
past: [...past, present],
present: newPresent,
future: []
}
})
}, [])
const reset = useCallback((newPresent: T) => {
setState({
past: [],
present: newPresent,
future: []
})
}, [])
return [
state,
{redo, undo, set, reset, canRedo, canUndo}
] as const
}
4.用useReducer進(jìn)行狀態(tài)管理
替代方案:
useReducer
作為useState
的替代方案。它接收一個(gè)形如 (state, action) => newState
的 reducer,并返回當(dāng)前的 state 以及與其配套的 dispatch 方法。
相比較于useState
,useReducer
具有如下優(yōu)點(diǎn):
-
state
中的狀態(tài)值之間相互關(guān)聯(lián); - 下一個(gè)
state
的更新依賴于之前的state
。
- useReducer | Hook API 索引 – React
下面使用 useReducer
再對 use-undo
進(jìn)行改寫
編輯 src\utils\use-undo.ts
:
import { useCallback, useReducer, useState } from "react";
const UNDO = 'UNDO'
const REDO = 'REDO'
const SET = 'SET'
const RESET = 'RESET'
type State<T> = {
past: T[];
present: T;
future: T[];
}
type Action<T> = { newPresent?: T, type: typeof UNDO | typeof REDO | typeof SET | typeof RESET }
const undoReducer = <T>(state: State<T>, action: Action<T>) => {
const { past, present, future } = state
const { newPresent, type } = action
switch(type) {
case UNDO: {
if (past.length === 0) return state;
const previous = past[past.length - 1];
const newPast = past.slice(0, past.length - 1);
return {
past: newPast,
present: previous,
future: [present, ...future],
};
}
case REDO: {
if (future.length === 0) return state;
const next = future[0];
const newFuture = future.slice(1);
return {
past: [...past, present],
present: next,
future: newFuture,
};
}
case SET: {
if (newPresent === present) {
return state;
}
return {
past: [...past, present],
present: newPresent,
future: [],
};
}
case RESET: {
return {
past: [],
present: newPresent,
future: [],
}
}
default:
return state
}
}
export const useUndo = <T>(initialPresent: T) => {
const [state, dispatch] = useReducer(undoReducer, {
past: [],
present: initialPresent,
future: [],
} as State<T>)
const canUndo = state.past.length !== 0;
const canRedo = state.future.length !== 0;
const undo = useCallback(() => dispatch({ type: UNDO }), []);
const redo = useCallback(() => dispatch({ type: REDO }), []);
const set = useCallback((newPresent: T) => dispatch({newPresent, type: SET}), []);
const reset = useCallback((newPresent: T) => dispatch({newPresent, type: RESET}), []);
return [state, { redo, undo, set, reset, canRedo, canUndo }] as const;
};
統(tǒng)一狀態(tài)管理后 雖然代碼量多了,但是經(jīng)過多重封裝,層次更加清晰
可以發(fā)現(xiàn) useReducer
相對 useState
適合定義多個(gè)相互影響的狀態(tài)量
鑒于 useReducer
針對復(fù)雜的state關(guān)系和更新的前后依賴的優(yōu)勢,因此 useAsync
非常適合使用 useReducer
來重構(gòu)
接下來使用 useReducer
改造一下 與 use-undo
結(jié)構(gòu)類似的 use-async
(src\utils\use-async.ts
):文章來源:http://www.zghlxwxcb.cn/news/detail-622223.html
...
const useSafeDispatch = <T>(dispatch: (...args: T[]) => void) => {
const mountedRef = useMountedRef()
return useCallback((...args: T[]) => (mountedRef.current ? dispatch(...args) : void 0), [dispatch, mountedRef])
}
export const useAsync = <D>(...) => {
const config = { ...defaultConfig, ...initialConfig };
const [state, dispatch] = useReducer((state: State<D>, action: Partial<State<D>>) => ({...state, ...action}), {
...defaultInitialState,
...initialState,
});
const safeDispatch = useSafeDispatch(dispatch);
const [rerun, setRerun] = useState(() => () => {});
const setData = useCallback(
(data: D) =>
safeDispatch(...),
[safeDispatch]
);
const setError = useCallback(
(error: Error) =>
safeDispatch(...),
[safeDispatch]
);
// run 來觸發(fā)異步請求
const run = useCallback(
(...) => {
...
safeDispatch({ stat: "loading" });
return promise
.then((data) => {
setData(data);
return data;
})
.catch(...);
},
[config.throwOnError, safeDispatch, setData, setError]
);
...
};
部分引用筆記還在草稿階段,敬請期待。。。文章來源地址http://www.zghlxwxcb.cn/news/detail-622223.html
到了這里,關(guān)于【實(shí)戰(zhàn)】 九、深入React 狀態(tài)管理與Redux機(jī)制(二) —— React17+React Hook+TS4 最佳實(shí)踐,仿 Jira 企業(yè)級項(xiàng)目(十七)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!