alibaba / hooks

A high-quality & reliable React Hooks library. https://ahooks.pages.dev/
https://ahooks.js.org/
MIT License
14.06k stars 2.71k forks source link

是否考虑添加一个 useManualHistoryTravel 来手动的记录状态 #2272

Open Debbl opened 1 year ago

Debbl commented 1 year ago

类似于 VueUse 的 useManualRefHistory

我用已有的 useHistoryTravel 简单实现了一下

import { useHistoryTravel } from "ahooks";
import { useEffect, useMemo, useState } from "react";

const useManualHistoryTravel = <T>(initialValue: T) => {
  const { value, setValue, back, forward, reset } =
    useHistoryTravel<T>(initialValue);
  const [state, setState] = useState<T>(initialValue);

  useEffect(() => value && setState(value), [value]);

  const actions = useMemo(
    () => ({
      commit: (newState?: T) => {
        setValue(newState ?? state);
      },
    }),
    [setValue, state]
  );

  return {
    value: state,
    setState,
    back,
    forward,
    reset,
    ...actions,
  } as const;
};

export default useManualHistoryTravel;
liuyib commented 1 year ago

可以考虑。在原来的 useHistoryTravel 上加个参数,比如 manual: boolean, 实现手动就可以了,没必要新加 hook (目前已经支持)。

类似的, VueUse 的 useDebouncedRefHistory useThrottledRefHistory 都可以通过加参数在 ahooks 中实现

Debbl commented 1 year ago

如果加一个参数的话是不是会有点麻烦,设置 manual: true 后,导出的值是不是会变化,是不是会覆盖原本的用法,如这个 useManualHistoryTravel 我既想用 setState 又想用 commit,是我在设置 true 后才会有这个 commit 导出

liuyib commented 1 year ago

我既想用 setState 又想用 commit

现有的 useHistoryTravel 已经满足你的这个需求了,见 demo:https://codesandbox.io/s/ahooks-issue-2272-cpkh7s

另外,写这个 demo 时我发现,目前的已经支持手动提交记录了,就看你怎么用 setValue 了。直接 onChange 中调用 setValue 就是自动。onChange 里把值暂存到另一个 useState 中,然后再在其他地方手动 setValue,就是手动。

Debbl commented 1 year ago

是的,我这个 useManualRefHistory, 就是用原有的 useHistoryTravel 来实现的。https://codesandbox.io/s/ahooks-issue-2272-cpkh7s 这个不是我想要的需求,我想要这个 state 是需要关心的数据用 value 来记录, https://codesandbox.io/s/ahooks-issue-2272-forked-4gn284 ,我当前是添加一个 useEffect 实现的,感觉有一些复杂。所以我才需要添加一个 hook,如果你认为没有必要就算了

liuyib commented 1 year ago

需要关心的数据用 value 来记录

这样吗?(既能自动保存,又能手动保存,数据是用 value 来记录)https://codesandbox.io/s/ahooks-issue-2272-demo2-h2l2t8?file=/App.tsx:119-127

Debbl commented 1 year ago

我的需求是 back 和 forward 只记录 commit 调用后的数据,在调用 commit 后才会记录当前的状态,https://codesandbox.io/s/ahooks-issue-2272-demo2-h2l2t8?file=/App.tsx:119-127 但是这里例子把所有的 setState 的值都记录了。https://github.com/Debbl/svg-drawing 这个是写的一个小项目,我需要在鼠标移动是添加 line 并且更新 lines,在鼠标抬起时记录当前的 lines 数据。下面是我自己写的一个 hook。

import { useHistoryTravel } from "ahooks";
import { useEffect, useMemo, useState } from "react";

const useManualHistoryTravel = <T>(initialValue: T) => {
  const { value, setValue, ..._actions } = useHistoryTravel<T>(initialValue);
  const [state, setState] = useState<T>(initialValue);

  useEffect(() => value && setState(value), [value]);

  const actions = useMemo(
    () => ({
      commit: (newState?: T) => {
        setValue(newState ?? state);
      },
    }),
    [setValue, state]
  );

  return {
    value: state,
    setState,
    ..._actions,
    ...actions,
  } as const;
};

export default useManualHistoryTravel;
liuyib commented 1 year ago

@Debbl 我理解你的需求了,感谢提供的 demo 项目,很 nice。确实有必要支持一下手动 commit,至于通过加参数支持,还是新 hook,我更倾向于通过加参数。

我后面处理下,有兴趣你也可以来个 PR 支持下,我来 review~

Debbl commented 1 year ago

@liuyib 你有空可以看一下,辛苦了

vaynevayne commented 12 months ago

直接招炒别人的设计就行了, 还想什么 https://github.com/xplato/useUndoable