问题
setState有回调函数,可以取得最新的state,而hooks的useState没有回调,不能立即取得最新值,这是由于useState的Capture value的特性造成的,网上解释挺多的,这里就不展开了。
解决方式
核心是通过ref来接收state,ref不受Capture value的影响且可以在作用域内访问
源码
取得最新值
2019年了,整理了N个实用案例帮你快速迁移到React Hooks
整挺好的,我只用ts重写一遍,后面继续用
import {
useState,
useRef,
useCallback,
Dispatch,
SetStateAction,
MutableRefObject
} from 'react';
const useRefState=<T>(
initialState: T | (() => T)
): [T, Dispatch<SetStateAction<T>>, MutableRefObject<T>] {
const ins = useRef<any>();
const [state, setState] = useState(() => {
// 初始化
const value =
typeof initialState === 'function'
? (initialState as () => T)()
: initialState;
ins.current = value;
return value;
});
const setValue = useCallback(value => {
if (typeof value === 'function') {
setState(prevState => {
const finalValue = value(prevState);
ins.current = finalValue;
return finalValue;
});
} else {
ins.current = value;
setState(value);
}
}, []);
return [state, setValue, ins];
}
export default useRefState;
回调函数
结合上面的hooks
import { useEffect, useRef, MutableRefObject } from 'react';
import useRefState from './useRefState';
const useCBState = <T>(
initState: T | (() => T)
): [
T,
(state: T | ((prev: T) => T), cb: () => any) => void,
MutableRefObject<T|undefined>
] => {
const [state, setState, ins] = useRefState(initState);
let isUpdate = useRef<any>();
const setCBState = (state: T | ((prev: T) => T), cb: () => any) => {
setState(prev => {
isUpdate.current = cb;
return typeof state === 'function'
? (state as (prev: T) => T)(prev)
: state;
});
};
useEffect(() => {
if (isUpdate.current) {
isUpdate.current();
}
});
return [state, setCBState, ins];
};
export default useCBState;
实际上,到这里差不多就完了,要完全实现setState的功能即在回调函数里取得最新值,也可以把最新值放到它的函数作用域内。