hooks中实现class的setState的效果

3,317 阅读1分钟

hooks迁移-实现class中setState的效果

问题

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的功能即在回调函数里取得最新值,也可以把最新值放到它的函数作用域内。