You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React自定义Hook获取数据返回旧值:如何让resolveOptions获正确结果?

问题分析

原代码的核心问题是:

  • data是一个一次性创建的Promise,它会立即用当前的dataRef.current值resolve,后续dataRef更新时,这个Promise不会重新生成,所以resolveOptions里拿到的永远是旧值。
  • getData仅触发state更新和服务器请求,但无法让resolveOptions等待这次异步请求的结果返回。
修改方案

我们需要让每次调用getData时,都能获取到对应搜索请求的最新结果,而非复用旧的Promise。可以通过以下步骤修改:

1. 重构usePromise钩子,让getData返回Promise

把usePromise改成每次调用getData时,返回一个等待当前搜索结果的Promise,同时用ref跟踪当前活跃的请求,避免旧请求干扰:

export const MyComponent = () => {
  const { getData } = usePromise();

  const usePromise = () => {
    const [searchValue, setSearchValue] = useState<string>();
    // 用ref跟踪当前请求的resolve函数
    const resolveRef = useRef<(value: string[]) => void>();

    const { results } = useHookToFetchDataFromServer({ filter: { field: searchValue } });

    useEffect(() => {
      if (results && resolveRef.current) {
        const items = results.items.map(item => item.label);
        // 触发当前请求的Promise resolve
        resolveRef.current(items);
        // 清空ref,避免重复触发
        resolveRef.current = undefined;
      }
    }, [results]);

    const getData = (searchVal: string): Promise<string[]> => {
      setSearchValue(searchVal);
      // 返回一个新的Promise,把resolve函数存在ref里
      return new Promise((resolve) => {
        resolveRef.current = resolve;
      });
    };

    return { getData };
  };

  const resolveOptions = async (search: string): Promise<string[]> => {
    // 直接等待getData返回的Promise,拿到当前搜索的最新结果
    const res = await getData(search);
    console.log(res); // 现在会显示当前搜索的正确结果
    return res;
  };

  return (<MyChildComponent optionsResolver={resolveOptions} />);
};

2. 关键修改点说明

  • 移除了dataRef和固定的data Promise,改为每次调用getData时动态生成新的Promise,确保对应当前搜索请求。
  • 用resolveRef跟踪当前需要resolve的Promise回调,当服务器返回最新results时,触发回调返回结果。
  • resolveOptions改为异步函数,直接等待getData的返回值,确保拿到当前搜索的最新结果。

额外优化:处理竞态问题

如果用户快速连续搜索,可能出现旧请求比新请求晚返回的情况,可通过跟踪当前搜索值过滤旧结果:

const usePromise = () => {
  const [searchValue, setSearchValue] = useState<string>();
  const resolveRef = useRef<(value: string[]) => void>();
  // 跟踪当前正在等待的搜索值
  const currentSearchRef = useRef<string>();

  const { results } = useHookToFetchDataFromServer({ filter: { field: searchValue } });

  useEffect(() => {
    if (results && resolveRef.current && currentSearchRef.current === searchValue) {
      const items = results.items.map(item => item.label);
      resolveRef.current(items);
      resolveRef.current = undefined;
    }
  }, [results, searchValue]);

  const getData = (searchVal: string): Promise<string[]> => {
    setSearchValue(searchVal);
    currentSearchRef.current = searchVal;
    return new Promise((resolve) => {
      resolveRef.current = resolve;
    });
  };

  return { getData };
};

这样就能确保只有当前搜索值对应的结果才会被resolve,避免竞态导致的旧结果覆盖新结果。

内容的提问来源于stack exchange,提问作者Vlad Suciu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 13:05:18