ahooks
Version:
react hooks library
102 lines (101 loc) • 2.92 kB
JavaScript
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) => {
const _past = [...past, 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);
}
setHistory({
present: val,
future: [],
past: _past,
});
};
const _forward = (step = 1) => {
if (future.length === 0) {
return;
}
const { _before, _current, _after } = split(step, future);
setHistory({
past: [...past, present, ..._before],
present: _current,
future: _after,
});
};
const _backward = (step = -1) => {
if (past.length === 0) {
return;
}
const { _before, _current, _after } = split(step, past);
setHistory({
past: _before,
present: _current,
future: [..._after, present, ...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),
};
}