react hooks確實很好用,程式碼相比class元件也會簡潔一些,但有時候也會覺得對useState的資料更新時有不太方便的地方,比如宣告陣列或者物件的時候,在設定的時候就得傳一個函式回去,並且使用擴充套件運算子合並物件
setValue((oldValue) => ({
...oldValue,
...newValue,
}));
感覺在元件裡這樣看著不是太美觀,並且如果元件程式碼多一點的時候,更新一下資料需要佔用三行,尤其在if/for或者回撥裡面使用的時候看著更是難受,於是決定對useState做一下簡單的封裝,讓元件裡更新資料時更優雅一些。
首先寫幾個工具函式isArray、isObject、isNotObject
function isArray(value) {
return value instanceof Array;
}
function isObject(value) {
return value instanceof Object && !(value instanceof Array);
}
function isNotObject(value) {
return typeof value !== "object";
}
然後在我們的自定義hook函式useSetState中,用原聲的useState宣告變數,變數可以直接返回,只需對_setValue做一些操作返回一個新的setValue。
在setValue中,如果initValue為陣列,那新的setValue在傳入單個值時進行push,傳入陣列時進行合併;如果initValue為物件,傳入物件合併,傳入其他型別則丟擲錯誤。
import { useState } from "react";
export default function useSetState(initValue) {
const [_value, _setValue] = useState(initValue);
function setValue(newValue) {
// 初始資料為 陣列
if (isArray(initValue)) {
if (isArray(newValue)) {
_setValue((oldValue) => [...oldValue, ...newValue]);
} else {
_setValue((oldValue) => [...oldValue, newValue]);
}
}
// 初始資料為 物件
else if (isObject(initValue)) {
if (isObject(newValue)) {
_setValue((oldValue) => ({
...oldValue,
...newValue,
}));
} else {
throw new Error(`${JSON.stringify(newValue)} 與初始資料型別不符!`);
}
} else if (isNotObject(initValue)) {
_setValue(newValue);
}
}
return [_value, setValue];
}
實際使用效果
const [obj, setObj] = useSetState({
a: 1,
b: 2,
});
const [arr, setArr] = useSetState([{ id: 1 }, { id: 2 }]);
setObj({ c: 3 }); // {a: 1, b: 2, c: 3}
setArr({ id: 3 }); // [{ id: 1 }, { id: 2 },{ id: 3 }]