有状态自定义钩子

问题描述 投票:0回答:1

我有一个组件

StatusIndicator
,它使用 Redux Toolkit 查询
q
来获取状态值并显示它。

我想编写一个自定义挂钩

usePolling
,可以使用参数进行配置以定期调用
q
,更新
StatusIndicator

我有两个问题:

  1. 即使我指定了对
    isAuthenticated
    的依赖,自定义挂钩的内容也会重复运行。
  2. 如何分离自定义钩子的每个实例的状态?我正在使用 useState 来尝试维护每个实例的
    timeoutId
    。这是正确的吗?
export const StatusIndicator = () => {
  const isAuthenticated = useSelector((state) => state.auth.token);
  const { data, q } = useGetStatusQuery();

  usePolling({ callback: q }, [isAuthenticated]);

  return (<div>{{data.status}}</div>);
};

export const usePolling = ({ callback }, dependencies = []) => {
  const [instanceTimeoutId, setInstanceTimeoutId] = useState(null);

  // I only want this run when `isAuthenticated` changes
  useEffect(() => {
    (async function continuation() {
      clearTimeout(instanceTimeoutId);
      await callback();
      const { timeoutId, promise } = delay(interval);
      setInstanceTimeoutId(timeoutId);
      await promise;
      continuation();
    })();

    return () => clearTimeout(instanceTimeoutId);
  }, [...dependencies]);
};
javascript reactjs hook
1个回答
0
投票

正如我在评论中提到的,您使用

useState
作为超时句柄,因此每次调用
continuation
函数时,它都会调用
setInstanceTimeoutId
,这将触发
usePolling 的重新渲染
由于状态改变而挂钩。

事实上,这里只需要一个简单的变量就足够了。您可能可以使用

useRef
作为句柄,但我认为简单的
let timeoutHandle
应该没有问题,因为我们只在两个地方使用该值 - 在
continuation
内和钩子清理中。两者都只会访问当时的当前值。

export const usePolling = ({ callback }, dependencies = []) => {
  
  useEffect(() => {
    let timeoutHandle = null;
    (async function continuation() {
      clearTimeout(timeoutHandle);
      await callback();
      const { timeoutId, promise } = delay(interval);
      timeoutHandle = timeoutId;
      await promise;
      continuation();
    })();
    return () => clearTimeout(timeoutHandle);
  }, [...dependencies]);
};
© www.soinside.com 2019 - 2024. All rights reserved.