回调时过时的自定义挂钩状态 属性

Stale custom hook state property on callback

我的 React 应用程序中有一个自定义挂钩,它公开了一个函数 (hookFn) 来计算 value。一旦更新了值(状态更改、触发 useEffect),挂钩就会通过回调函数提醒应用程序。问题是:在我的回调函数中,我希望能够通过 hook.value 访问该值,但它似乎已经过时了!尽管我知道值状态已更新!

Codesandbox:https://codesandbox.io/s/stoic-payne-bwp6j5?file=/src/App.js:0-910

import { useEffect, useRef, useState } from "react";

export default function App() {
  const hook = useCustomHook();

  useEffect(() => {
    hook.hookFn(hookCallback);
  }, []);

  function hookCallback(value) {
    console.log({givenValue: value, hookValue: hook.value});
  }

  return "See console for output";
}

function useCustomHook() {
  const callbackRef = useRef(null);
  const [value, setValue] = useState("initial value");

  useEffect(() => {
    if (callbackRef.current) {
      callbackRef.current(value);
    }
  }, [value]);

  function hookFn(callbackFn) {
    callbackRef.current = callbackFn;
    setValue("value set in hookFn");
  }

  return { hookFn, value };
}

仅供参考:在我的实际应用中,该挂钩用于搜索,随着更多搜索结果可用,它可能会多次调用回调函数。

有什么方法可以确保hook.value有效吗?还是一般情况下挂钩公开状态变量是不好的做法?

事实证明 hook.value 是陈旧的,因为当我从 hookCallback 访问它时 hook 是陈旧的。每次在我的自定义挂钩中发生状态更改时,useCustomHook 都会生成一个新对象。

然后,复杂的解决方案是为 hook 创建一个 ref 并在 useEffect 中保持最新。但是我必须确保在访问 hookRef.current.value 之前等待 useEffect 到 运行...这是我尝试完成这项工作的尝试:https://codesandbox.io/s/dazzling-shirley-0r7k47?file=/src/App.js

但是,更好的解决方案是:不要混合 React 状态和手动回调。 相反,只需观察 useEffect 中的状态变化,如下所示:

import { useEffect, useState } from "react";

export default function App() {
  const hook = useCustomHook();

  useEffect(() => {
    hook.hookFn();
  }, []);

  useEffect(() => {
    if (hook.value) console.log({ hookValue: hook.value });
  }, [hook.value]);

  return "See console for output";
}

function useCustomHook() {
  const [value, setValue] = useState("initial value");

  function hookFn(callbackFn) {
    setValue("value set in hookFn");
  }

  return { hookFn, value };
}

请注意代码已简化,无需担心状态为 out-of-sync。