UNPKG

ahooks

Version:
108 lines (107 loc) • 3.26 kB
import { useRef, useState } from 'react'; import useMemoizedFn from '../useMemoizedFn'; import { isNumber } from '../utils'; const dumpIndex = (step, arr) => { 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; }; const split = (step, targetArr) => { const index = dumpIndex(step, targetArr); return { _current: targetArr[index], _before: targetArr.slice(0, index), _after: targetArr.slice(index + 1), }; }; export default function useHistoryTravel(initialValue, maxLength = 0) { const [history, setHistory] = useState({ present: initialValue, past: [], future: [], }); const { present, past, future } = history; const initialValueRef = useRef(initialValue); const reset = (...params) => { const _initial = params.length > 0 ? params[0] : initialValueRef.current; initialValueRef.current = _initial; setHistory({ present: _initial, future: [], past: [], }); }; const updateValue = (val) => { setHistory((current) => { const _past = [...current.past, current.present]; const maxLengthNum = isNumber(maxLength) ? maxLength : Number(maxLength); // maximum number of records exceeded if (maxLengthNum > 0 && _past.length > maxLengthNum) { //delete first _past.splice(0, 1); } return { present: val, future: [], past: _past, }; }); }; const _forward = (step = 1) => { setHistory((current) => { if (current.future.length === 0) { return current; } const { _before, _current, _after } = split(step, current.future); return { past: [...current.past, current.present, ..._before], present: _current, future: _after, }; }); }; const _backward = (step = -1) => { setHistory((current) => { if (current.past.length === 0) { return current; } const { _before, _current, _after } = split(step, current.past); return { past: _before, present: _current, future: [..._after, current.present, ...current.future], }; }); }; const go = (step) => { const stepNum = isNumber(step) ? step : Number(step); if (stepNum === 0) { return; } if (stepNum > 0) { return _forward(stepNum); } _backward(stepNum); }; return { value: present, backLength: past.length, forwardLength: future.length, setValue: useMemoizedFn(updateValue), go: useMemoizedFn(go), back: useMemoizedFn(() => { go(-1); }), forward: useMemoizedFn(() => { go(1); }), reset: useMemoizedFn(reset), }; }