From 863e974e169ef1c518a2442db2248b6da7fa59f0 Mon Sep 17 00:00:00 2001 From: Debbl Date: Wed, 2 Aug 2023 20:27:22 +0800 Subject: [PATCH 1/5] feat: useHistoryTravel add manual option --- packages/hooks/src/useHistoryTravel/index.ts | 31 ++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/hooks/src/useHistoryTravel/index.ts b/packages/hooks/src/useHistoryTravel/index.ts index 24124fa543..1f3c497d8b 100644 --- a/packages/hooks/src/useHistoryTravel/index.ts +++ b/packages/hooks/src/useHistoryTravel/index.ts @@ -31,7 +31,25 @@ const split = (step: number, targetArr: T[]) => { }; }; -export default function useHistoryTravel(initialValue?: T, maxLength: number = 0) { +export default function useHistoryTravel( + initialValue?: T, + options?: + | { + maxLength: number; + manual: boolean; + } + | number, +) { + let maxLength = 0; + let manual = false; + + if (typeof options === 'number') { + maxLength = options; + } else if (typeof options === 'object') { + maxLength = options.maxLength; + manual = options.manual; + } + const [history, setHistory] = useState>({ present: initialValue, past: [], @@ -69,6 +87,14 @@ export default function useHistoryTravel(initialValue?: T, maxLength: number }); }; + const updateValueWithoutRecord = (val: T) => { + setHistory({ + present: val, + future: future, + past: past, + }); + }; + const _forward = (step: number = 1) => { if (future.length === 0) { return; @@ -109,7 +135,8 @@ export default function useHistoryTravel(initialValue?: T, maxLength: number value: present, backLength: past.length, forwardLength: future.length, - setValue: useMemoizedFn(updateValue), + setValue: manual ? useMemoizedFn(updateValueWithoutRecord) : useMemoizedFn(updateValue), + commit: useMemoizedFn(updateValue), go: useMemoizedFn(go), back: useMemoizedFn(() => { go(-1); From c82934aaa5d930a42b649406d93e7286d0d36acf Mon Sep 17 00:00:00 2001 From: Debbl Date: Wed, 2 Aug 2023 21:32:31 +0800 Subject: [PATCH 2/5] feat: add doc and test --- .../useHistoryTravel/__tests__/index.test.ts | 49 +++++++++++++++++ .../hooks/src/useHistoryTravel/demo/demo4.tsx | 52 +++++++++++++++++++ .../hooks/src/useHistoryTravel/index.en-US.md | 35 +++++++++++-- packages/hooks/src/useHistoryTravel/index.ts | 28 ++++++---- .../hooks/src/useHistoryTravel/index.zh-CN.md | 35 +++++++++++-- 5 files changed, 181 insertions(+), 18 deletions(-) create mode 100644 packages/hooks/src/useHistoryTravel/demo/demo4.tsx diff --git a/packages/hooks/src/useHistoryTravel/__tests__/index.test.ts b/packages/hooks/src/useHistoryTravel/__tests__/index.test.ts index a9be55d558..969519068c 100644 --- a/packages/hooks/src/useHistoryTravel/__tests__/index.test.ts +++ b/packages/hooks/src/useHistoryTravel/__tests__/index.test.ts @@ -242,4 +242,53 @@ describe('useHistoryTravel', () => { expect(hook.result.current.backLength).toBe(0); expect(hook.result.current.value).toBe(90); }); + + it('should work with manual', async () => { + const hook = renderHook(() => useHistoryTravel(0, { manual: true })); + + act(() => { + hook.result.current.setValue(1); + }); + // <0> + // 1 + expect(hook.result.current.forwardLength).toBe(0); + expect(hook.result.current.backLength).toBe(0); + expect(hook.result.current.value).toBe(1); + + act(() => { + hook.result.current.commit(); + }); + // 0 <1> + // 1 + expect(hook.result.current.forwardLength).toBe(0); + expect(hook.result.current.backLength).toBe(1); + expect(hook.result.current.value).toBe(1); + + act(() => { + hook.result.current.commit(2); + }); + // 0 1 <2> + // 2 + expect(hook.result.current.forwardLength).toBe(0); + expect(hook.result.current.backLength).toBe(2); + expect(hook.result.current.value).toBe(2); + + act(() => { + hook.result.current.back(); + }); + // 0 <1> 2 + // 1 + expect(hook.result.current.forwardLength).toBe(1); + expect(hook.result.current.backLength).toBe(1); + expect(hook.result.current.value).toBe(1); + + act(() => { + hook.result.current.forward(); + }); + // 0 1 <2> + // 2 + expect(hook.result.current.forwardLength).toBe(0); + expect(hook.result.current.backLength).toBe(2); + expect(hook.result.current.value).toBe(2); + }); }); diff --git a/packages/hooks/src/useHistoryTravel/demo/demo4.tsx b/packages/hooks/src/useHistoryTravel/demo/demo4.tsx new file mode 100644 index 0000000000..69cfd935e2 --- /dev/null +++ b/packages/hooks/src/useHistoryTravel/demo/demo4.tsx @@ -0,0 +1,52 @@ +/** + * title: Manually record history operations + * desc: Only when you click commit, the current data will be recorded. + * + * title.zh-CN: 手动记录历史操作 + * desc.zh-CN: 只有点击 commit 后,才会记录当前的数据。 + */ + +import { useHistoryTravel } from 'ahooks'; +import React from 'react'; + +export default () => { + const { value, setValue, commit, backLength, forwardLength, back, forward } = + useHistoryTravel(0, { + manual: true, + }); + + const increment = () => { + setValue(value ?? 0 + 1); + }; + const decrement = () => { + setValue(value ?? 0 - 1); + }; + + return ( +
+
Count: {value}
+
+
+ + +
+
{'/'}
+
+ + + +
+
+
+ ); +}; diff --git a/packages/hooks/src/useHistoryTravel/index.en-US.md b/packages/hooks/src/useHistoryTravel/index.en-US.md index 17cf25085c..dd6d0faa12 100644 --- a/packages/hooks/src/useHistoryTravel/index.en-US.md +++ b/packages/hooks/src/useHistoryTravel/index.en-US.md @@ -35,12 +35,38 @@ const { } = useHistoryTravel(initialValue?: T, maxLength: number = 0 ); ``` +```typescript +const { + value, + setValue, + commit, + backLength, + forwardLength, + go, + back, + forward +} = useHistoryTravel( + initialValue?: T, + options?: { + maxLength?: number; + manual?: boolean; + }); +``` + ### Params -| Property | Description | Type | Default | -| ------------ | ------------------------------------------------------------------------------------------------------------------------- | -------- | ----------- | -| initialValue | Optional initial value | `T` | - | -| maxLength | Optional limit the maximum length of history records. If the maximum length is exceeded, the first record will be deleted | `number` | 0 unlimited | +| Property | Description | Type | Default | +| ------------ | ------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- | +| initialValue | Optional initial value | `T` | - | +| maxLength | Optional limit the maximum length of history records. If the maximum length is exceeded, the first record will be deleted | `number` | 0 unlimited | +| options | Options | `Options` | - | + +### Options + +| Property | Description | Type | Default | +| --------- | ------------------------------------------------------------------------------------------------------------------------- | --------- | ----------- | +| maxLength | Optional limit the maximum length of history records. If the maximum length is exceeded, the first record will be deleted | `number` | 0 unlimited | +| manual | Optional Whether to manually submit the record through `commit` | `boolean` | false | ### Result @@ -48,6 +74,7 @@ const { | ------------- | --------------------------------------------------------------------------------- | ------------------------------- | | value | Current value | `T` | | setValue | Set value | `(value: T) => void` | +| commit | Manually submit records | `(value: T) => void` | | backLength | The length of backward history | `number` | | forwardLength | The length of forward history | `number` | | go | Move between the history, move backward on step < 0,and move forward on step > 0 | `(step: number) => void` | diff --git a/packages/hooks/src/useHistoryTravel/index.ts b/packages/hooks/src/useHistoryTravel/index.ts index 1f3c497d8b..d0c6cf92db 100644 --- a/packages/hooks/src/useHistoryTravel/index.ts +++ b/packages/hooks/src/useHistoryTravel/index.ts @@ -35,8 +35,8 @@ export default function useHistoryTravel( initialValue?: T, options?: | { - maxLength: number; - manual: boolean; + maxLength?: number; + manual?: boolean; } | number, ) { @@ -46,8 +46,8 @@ export default function useHistoryTravel( if (typeof options === 'number') { maxLength = options; } else if (typeof options === 'object') { - maxLength = options.maxLength; - manual = options.manual; + maxLength = options?.maxLength || maxLength; + manual = options?.manual || manual; } const [history, setHistory] = useState>({ @@ -71,7 +71,7 @@ export default function useHistoryTravel( }); }; - const updateValue = (val: T) => { + const updateValue = useMemoizedFn((val: T) => { const _past = [...past, present]; const maxLengthNum = isNumber(maxLength) ? maxLength : Number(maxLength); // maximum number of records exceeded @@ -85,15 +85,23 @@ export default function useHistoryTravel( future: [], past: _past, }); - }; + }); - const updateValueWithoutRecord = (val: T) => { + const updateValueWithoutRecord = useMemoizedFn((val?: T) => { setHistory({ present: val, future: future, past: past, }); - }; + }); + + const commit = useMemoizedFn((val?: T) => { + if (val) { + updateValue(val); + return; + } + return present && updateValue(present); + }); const _forward = (step: number = 1) => { if (future.length === 0) { @@ -135,8 +143,8 @@ export default function useHistoryTravel( value: present, backLength: past.length, forwardLength: future.length, - setValue: manual ? useMemoizedFn(updateValueWithoutRecord) : useMemoizedFn(updateValue), - commit: useMemoizedFn(updateValue), + setValue: manual ? updateValueWithoutRecord : updateValue, + commit, go: useMemoizedFn(go), back: useMemoizedFn(() => { go(-1); diff --git a/packages/hooks/src/useHistoryTravel/index.zh-CN.md b/packages/hooks/src/useHistoryTravel/index.zh-CN.md index 2227d1d20e..f93f6f62f2 100644 --- a/packages/hooks/src/useHistoryTravel/index.zh-CN.md +++ b/packages/hooks/src/useHistoryTravel/index.zh-CN.md @@ -35,12 +35,38 @@ const { } = useHistoryTravel(initialValue?: T, maxLength: number = 0); ``` +```typescript +const { + value, + setValue, + commit, + backLength, + forwardLength, + go, + back, + forward +} = useHistoryTravel( + initialValue?: T, + options?: { + maxLength?: number; + manual?: boolean; + }); +``` + ### Params -| 参数 | 说明 | 类型 | 默认值 | -| ------------ | --------------------------------------------------------- | -------- | -------- | -| initialValue | 可选,初始值 | `any` | - | -| maxLength | 可选,限制历史记录最大长度,超过最大长度后将删除第一个记录 | `number` | 0 不限制 | +| 参数 | 说明 | 类型 | 默认值 | +| ------------ | --------------------------------------------------------- | --------- | -------- | +| initialValue | 可选,初始值 | `any` | - | +| maxLength | 可选,限制历史记录最大长度,超过最大长度后将删除第一个记录 | `number` | 0 不限制 | +| options | 可选,配置项 | `Options` | - | + +### Options + +| 参数 | 说明 | 类型 | 默认值 | +| --------- | --------------------------------------------------------- | --------- | -------- | +| maxLength | 可选,限制历史记录最大长度,超过最大长度后将删除第一个记录 | `number` | 0 不限制 | +| manual | 可选,是否通过 commit 手动提交记录 | `boolean` | false | ### Result @@ -48,6 +74,7 @@ const { | ------------- | --------------------------------------------- | ------------------------------- | | value | 当前值 | `T` | | setValue | 设置 value | `(value: T) => void` | +| commit | 手动提交记录 | `(value: T) => void` | | backLength | 可回退历史长度 | `number` | | forwardLength | 可前进历史长度 | `number` | | go | 前进步数, step < 0 为后退, step > 0 时为前进 | `(step: number) => void` | From 2945af00383d8080833eccec66527359c7a887ab Mon Sep 17 00:00:00 2001 From: Brendan Dash <61053131+Debbl@users.noreply.github.com> Date: Thu, 3 Aug 2023 13:12:21 +0800 Subject: [PATCH 3/5] Update packages/hooks/src/useHistoryTravel/index.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 使用 ?? 操作符 Co-authored-by: 云泥 <1656081615@qq.com> --- packages/hooks/src/useHistoryTravel/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/hooks/src/useHistoryTravel/index.ts b/packages/hooks/src/useHistoryTravel/index.ts index d0c6cf92db..9beac1ab99 100644 --- a/packages/hooks/src/useHistoryTravel/index.ts +++ b/packages/hooks/src/useHistoryTravel/index.ts @@ -46,8 +46,8 @@ export default function useHistoryTravel( if (typeof options === 'number') { maxLength = options; } else if (typeof options === 'object') { - maxLength = options?.maxLength || maxLength; - manual = options?.manual || manual; + maxLength = options?.maxLength ?? maxLength; + manual = options?.manual ?? manual; } const [history, setHistory] = useState>({ From bb5b57ee18bec382e235860560b95d4c4965ade9 Mon Sep 17 00:00:00 2001 From: Brendan Dash <61053131+Debbl@users.noreply.github.com> Date: Thu, 3 Aug 2023 13:13:24 +0800 Subject: [PATCH 4/5] Update packages/hooks/src/useHistoryTravel/index.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 云泥 <1656081615@qq.com> --- packages/hooks/src/useHistoryTravel/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/hooks/src/useHistoryTravel/index.ts b/packages/hooks/src/useHistoryTravel/index.ts index 9beac1ab99..87681dc168 100644 --- a/packages/hooks/src/useHistoryTravel/index.ts +++ b/packages/hooks/src/useHistoryTravel/index.ts @@ -45,6 +45,9 @@ export default function useHistoryTravel( if (typeof options === 'number') { maxLength = options; + if (isDev) { + console.warn('[ahooks: useHistoryTravel] `maxLength` is deprecated which will be removed in next major version, please use `options.maxLength` instead.'); + } } else if (typeof options === 'object') { maxLength = options?.maxLength ?? maxLength; manual = options?.manual ?? manual; From 522ee8f55d27c6a58f21622f671c801c66ec8cb7 Mon Sep 17 00:00:00 2001 From: liuyib <1656081615@qq.com> Date: Thu, 3 Aug 2023 14:12:14 +0800 Subject: [PATCH 5/5] chore: import isDev --- packages/hooks/src/useHistoryTravel/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/hooks/src/useHistoryTravel/index.ts b/packages/hooks/src/useHistoryTravel/index.ts index 87681dc168..2482df752c 100644 --- a/packages/hooks/src/useHistoryTravel/index.ts +++ b/packages/hooks/src/useHistoryTravel/index.ts @@ -1,6 +1,7 @@ import { useRef, useState } from 'react'; import useMemoizedFn from '../useMemoizedFn'; import { isNumber } from '../utils'; +import isDev from '../utils/isDev'; interface IData { present?: T; @@ -45,8 +46,11 @@ export default function useHistoryTravel( if (typeof options === 'number') { maxLength = options; + if (isDev) { - console.warn('[ahooks: useHistoryTravel] `maxLength` is deprecated which will be removed in next major version, please use `options.maxLength` instead.'); + console.warn( + '[ahooks: useHistoryTravel] `maxLength` is deprecated which will be removed in next major version, please use `options.maxLength` instead.', + ); } } else if (typeof options === 'object') { maxLength = options?.maxLength ?? maxLength;