Vue重构:这可能是优雅的 vue useToggle

604 阅读1分钟

一. 研究 vant useToggle 源码,发现只支持布尔值,源码如下:

import { ref } from 'vue';

export function useToggle(defaultValue = false) {
  const state = ref(defaultValue);
  const toggle = (value = !state.value) => {
    state.value = value;
  };
  return [state, toggle] as const;
}

二. 又研究了a-hook useToggle 源码,发现洋洋洒洒70行(太繁琐了),源码如下:

import { ref, Ref } from 'vue-demi';

type IState = string | number | boolean | undefined;

export function useToggle<T = boolean | undefined>(): {
  state: Ref<boolean>;
  toggle: (value?: T) => void;
  setLeft: () => void;
  setRight: () => void;
};

export function useToggle<T = IState>(
  defaultValue: T,
): {
  state: Ref<T>;
  toggle: (value?: T) => void;
  setLeft: () => void;
  setRight: () => void;
};

export function useToggle<T = IState, U = IState>(
  defaultValue: T,
  reverseValue: U,
): {
  state: Ref<T | U>;
  toggle: (value?: T | U) => void;
  setLeft: () => void;
  setRight: () => void;
};

export function useToggle<D extends IState = IState, R extends IState = IState>(
  defaultValue: D = false as D,
  reverseValue?: R,
) {
  const state = ref<D | R>(defaultValue);

  const setState = (value: D | R) => {
    // TODO
    state.value = value as any;
  };

  const reverseValueOrigin = (reverseValue === undefined
    ? !defaultValue
    : reverseValue) as D | R;

  // 切换返回值
  const toggle = (value: D | R) => {
    if (value === undefined) {
      value = state.value === defaultValue ? reverseValueOrigin : defaultValue;
    }
    setState(value);
  };

  // 设置默认值
  const setLeft = () => {
    setState(defaultValue);
  };

  // 设置取反值
  const setRight = () => {
    setState(reverseValueOrigin);
  };

  return {
    state,
    toggle,
    setLeft,
    setRight,
  };
}

三. 就想要一种优雅、强大、极简的实现方式,最终实现如下:

  1. 默认是布尔值翻转;
  2. 支持任意翻转值对(数组支持的所有混合类型都支持);
import { ref } from 'vue';

const useToggle = (value = false, toggleValue = true) => {
  const state = ref(value);

  const toggle = (newValue) => {
    if ([value, toggleValue].includes(newValue)) {
      state.value = newValue;
      return;
    }
    
    state.value = (state.value === value ? toggleValue : value);
  }

  return {
    state,
    toggle
  }
}

export{
  useToggle,
}

🌰🌰:

// example:
// const { state, toggle } = useToggle();
// const { state: state1, toggle: toggle1} = useToggle("a", "b");
// const { state: state2, toggle: toggle2} = useToggle(1, null);