美文网首页
ahooks之useHistoryTravel详解

ahooks之useHistoryTravel详解

作者: 相遇一头猪 | 来源:发表于2022-02-10 20:04 被阅读0次

前言

ahooks是阿里开源的一个react hooks 工具库,其中包含了许多业务上能用到的自定义hooks。本文会介绍其中一个hooks —— useHistoryTravel的使用场景和讲解代码实现。

使用场景

从命名上看,它叫历史旅游,是用来管理状态变化历史。可以快速在状态变化历史中穿梭,方便实现撤销跟重做操作。

核心特性

● 撤销
● 重做
● 状态管理

实现

工具函数

useHistroyTravel内部用到2个自定义的工具函数:dumpIndexsplit

dumpIndex

dumpIndex接收一个数字step和arr数组,内部根据step的值和arr的大小生成一个index并返回。
● 正数处理:如果step > 0,index = step - 1 (为什么要减1,后面会讲)
● 负数处理:如果step < 0 , index = arr.length + step
● 边界限制: 0 <= index <= arr.length - 1

const dumpIndex = <T>(step: number, arr: T[]) => {
  let index =
    step > 0
      ? step - 1 // move forward
      : arr.length + step; // move backward
   if (index >= arr.length - 1) {
     index = arr.length - 1;
   }
   if (index < 0) {
     index = 0;
   }
   return index;
};

split

从函数命名就可以看出来了,这个函数的功能就是分裂,根据index把目标数组分成 过去、当前、未来 三部分。

  const split = <T>(step: number, targetArr: T[]) => {
    const index = dumpIndex(step, targetArr); //使用dumpIndex获取限制后的index
    
    return {
        _current: targetArr[index],
        _before: targetArr.slice(0, index),
        _after: targetArr.slice(index + 1)
    }
}

从代码中可以看出,dumpIndex得到的index是作为数组下标来使用的,所以也能解释为什么dumpIndex中step大于0需要减1。

类型

useHistoryTravel类型还是比较简单的,只有一个IData

interface IData<T> {
    present?: T;  // 当前的值
    past: T[];   // 保存过去值的数组
    future: T[];  // 保存未来值的数组
}

设计

useHistoryTravel内部结构很清晰,如下图:

image.png

present是初始值,pastfuture一开始是空数组。
接下来看看每个操作函数具体怎么做。

updateValue

首先是updateValue,对外命名是setValue
updateValue的作用是更新value,需要改变当前的present,并且把当前的present保存到past中。

  const updateValue = useCallback((val: T) => {
    setHistory({
        present: val,
        future: [],
        past: [...past, present]
    })
 },[history, setHistory]);

_backward & _forward

_backward,后退,默认后退一步。可根据入参step后退多少步,该函数不直接对外。

  const _backward = useCallback(
    (step: number = -1) => {
      if (past.length === 0) {
        return;
      }

      const { _before, _current, _after } = split(step, past);
      setHistory({
        past: _before,
        present: _current,
        future: [..._after, present, ...future]
      });
    },
    [history, setHistory]
  );

_forward,前进,默认前进一步。可根据入参step前进多少步,该函数不直接对外,和_backward一起被go函数使用。

  const _forward = useCallback(
    (step: number = 1) => {
      if (future.length === 0) {
        return;
      }
      const { _before, _current, _after } = split(step, future);
      setHistory({
        past: [...past, present, ..._before],
        present: _current,
        future: _after
      });
    },
    [history, setHistory]
  );

go

go函数执行状态跳转操作,内部根据入参step来决定使用_backward还是_forward

  const go = useCallback(
    (step: number) => {
      const stepNum = typeof step === 'number' ? step : Number(step);
      if (stepNum === 0) {
        return;
      }
      if (stepNum > 0) {
        return _forward(stepNum);
      }
      _backward(stepNum);
    },
    [_backward, _forward]
 );

reset

reset是用来重置当前history的,可以重置到初始值或者提供一个新的初始值。

  const reset = useCallback(
    (...params: any[]) => {
      const _initial = params.length > 0 ? params[0] : initialValueRef.current;
      initialValueRef.current = _initial;

      setHistory({
        present: _initial,
        future: [],
        past: []
      });
    },
    [history, setHistory]
  );

总结

useHistoryTravel代码结构清晰,功能完善,如果业务中有需要管理状态变化历史,可以放心使用。其实react中有一个hooks useReducer,使用useReducer来维护状态和集中管理action也能实现类似useHistoryTravel的功能。

相关文章

网友评论

      本文标题:ahooks之useHistoryTravel详解

      本文链接:https://www.haomeiwen.com/subject/xjlokrtx.html