useSetState
💡 Tips:管理对象类型的
state
场景
当我们想修改对象里的某个属性,而不影响其他属性,可以方便操作对象类型的 state
比如:传递给后端的数据用 object保存,当 setState 一个值,不影响其他值,就可以用这个 hook
案例
import React from "react";
import { useSetState } from "./hooks";
export default function App() {
const [state, setState] = useSetState({
name: "jack",
age: 18
});
const onClick = () => {
setState({ age: 20 });
};
return (
<>
<button onClick={onClick}>点我修改age</button>
<div className="App">{JSON.stringify(state, null, 2)}</div>
</>
);
}
核心代码
import { useCallback, useState } from "react";
const isFunction = (value: unknown): value is Function => typeof value === "function";
export type SetState<S extends Record<string, any>> = <K extends keyof S>(
state: Pick<S, K> | null | ((prevState: Readonly<S>) => Pick<S, K> | S | null)
) => void;
export const useSetState = <S extends Record<string, any>>(
initialState: S | (() => S)
): [S, SetState<S>] => {
const [state, setState] = useState<S>(initialState);
const setMergeState = useCallback((patch) => {
setState((prevState) => {
// 可以接受函数或者说是值,函数取函数调用的结果
const newState = isFunction(patch) ? patch(prevState) : patch;
// 只会进行一次浅合并
return newState ? { ...prevState, ...newState } : prevState;
});
}, []);
return [state, setMergeState];
};
useToggle
💡 Tips:管理在两个值之间切换的值
场景
model 框的控制显示隐藏值, 可以通过此 hook 方便管理
案例
import useToggle from "./hooks";
export default function App() {
const [state, actions] = useToggle("hello", "world");
const { toggle, set, setLeft, setRight } = actions;
return (
<>
<button onClick={toggle}>toggle</button>
<button onClick={() => set("heihei")}>set</button>
<button onClick={setLeft}>setLeft</button>
<button onClick={setRight}>setRight</button>
state: {state}
</>
);
}
核心代码
import { useMemo, useState } from 'react';
export interface Actions<T> {
setLeft: () => void;
setRight: () => void;
set: (value: T) => void;
toggle: () => void;
}
function useToggle<T = boolean>(): [boolean, Actions<T>];
function useToggle<T>(defaultValue: T): [T, Actions<T>];
function useToggle<T, U>(defaultValue: T, reverseValue: U): [T | U, Actions<T | U>];
function useToggle<D, R>(defaultValue: D = false as unknown as D, reverseValue?: R) {
const [state, setState] = useState<D | R>(defaultValue);
const actions = useMemo(() => {
// 获取reverse 的值,如果没给这个值,则取defaultValue的反值;
const reverseValueOrigin = (reverseValue === undefined ? !defaultValue : reverseValue) as D | R;
const toggle = () => setState((s) => (s === defaultValue ? reverseValueOrigin : defaultValue));
const set = (value: D | R) => setState(value);
const setLeft = () => setState(defaultValue);
const setRight = () => setState(reverseValueOrigin);
return {
toggle,
set,
setLeft,
setRight,
};
// useToggle ignore value change
// }, [defaultValue, reverseValue]);
}, []);
return [state, actions];
}
export default useToggle;
useBoolean
💡 Tips:优雅的管理布尔值。
场景
优雅管理 drawer 的显示隐藏
案例
import useBoolean from "./useBoolean";
export default function App() {
const [visible, actions] = useBoolean(false);
const { toggle } = actions;
return (
<div className="App">
<button onClick={toggle}>toggle</button>
{visible && <h1>Hello CodeSandbox</h1>}
</div>
);
}
核心代码
import { useMemo } from 'react';
import useToggle from '../useToggle';
export interface Actions {
setTrue: () => void;
setFalse: () => void;
set: (value: boolean) => void;
toggle: () => void;
}
export default function useBoolean(defaultValue = false): [boolean, Actions] {
const [state, { toggle, set }] = useToggle(defaultValue);
const actions: Actions = useMemo(() => {
const setTrue = () => set(true);
const setFalse = () => set(false);
return {
toggle,
set: (v) => set(!!v),
setTrue,
setFalse,
};
}, []);
return [state, actions];
}