【问题标题】:Memoize API response using useCallback hook使用 useCallback 钩子记忆 API 响应
【发布时间】:2020-09-08 14:31:47
【问题描述】:

当我单击一个按钮时,我需要在我的 React 项目中获取一个 API,但如果我再次单击它不应重做 API 调用,而是检索最新获取的数据。

我知道可以记忆功能的钩子useCallback。所以我只是将我的 API 调用放在 useCallback 中:

  const memoizedApiResponse = React.useCallback(async () => {
    console.log("fetch is called again :(");
    let response = await fetch("https://api.stackexchange.com/2.2/users?order=desc&sort=reputation&site=stackoverflow");

    return await response.text();
  }, []);

所以当我点击按钮时,我只是调用这个记忆函数:

import React from "react";

const App = () => {
  const [apiResponse, setApiResponse] = React.useState(undefined);

  const memoizedApiResponse = React.useCallback(async () => {
    console.log("fetch is called again :(");
    let response = await fetch(
      "https://api.stackexchange.com/2.2/users?order=desc&sort=reputation&site=stackoverflow"
    );

    return await response.text();
  }, []);

  const updateApiResult = async () => {
    const apiResponse = await memoizedApiResponse();
    setApiResponse(apiResponse);
  };

  return (
    <div className="App">
      <button onClick={updateApiResult}>fetch API</button>
      <p>{apiResponse}</p>
    </div>
  );
};

export default App;

但遗憾的是,每次单击都会发送请求(您可以在控制台中看到消息)。你知道如何使用useCallback 来记忆请求响应吗?

这是codesandbox的链接。

【问题讨论】:

  • 您是否试图阻止 函数 被多次创建或阻止数据被多次获取。 useCallback 使您不必在每次渲染时都创建一个函数。它不会记住它可能返回的数据。你仍然会继续调用 memoized 函数。
  • 最简单的解决方案是检查apiResponse 变量是否已经填充到updateApiResult

标签: javascript reactjs react-hooks


【解决方案1】:

memoizedApiResponse 不是它的名字所暗示的(一个记忆化的 API 响应),它是一个记忆化的函数,可以从 API 中获取数据。您只是在为自己创建将获取数据的函数,而不是实际检索数据。

此外,useCallback 可能不会为您节省多少。我建议您阅读这篇文章:When to useMemo and useCallback 它确实有助于了解其中一些记忆挂钩的作用以及它们何时真正帮助您。

我想你想要这个

import React from "react";

const App = () => {
  const [apiResponse, setApiResponse] = React.useState(undefined);
  
  const getData = async () => {
    if (apiResponse) {
      return apiResponse;
    }
  
    const response = await fetch("https://api.stackexchange.com/2.2/users?order=desc&sort=reputation&site=stackoverflow");
    const data = await response.text();
    setApiResponse(data);
  };

  return (
    <div className="App">
      <button onClick={getData}>fetch API</button>
      <p>{apiResponse}</p>
    </div>
  );
};

export default App;

【讨论】:

  • 哦,好的,我明白了。所以我想我需要为我的 API 调用实现一个存储。谢谢你的解释。
【解决方案2】:

useCallback 不记忆响应,它记忆渲染之间的函数声明。

在您的情况下,您只需要检查您是否已经有结果,修复您的代码并保留您需要使用参考的useCallback

const textRef = useRef(null);

const memoizedApiResponse = React.useCallback(async () => {
  if (textRef.current === null) {
    console.log("fetch is called");
    textRef.current = true;
    let response = await fetch("...");

    const text = await response.text();
    textRef.current = text;
    return text;
  }

  return textRef.current;
}, []);

【讨论】:

  • 感谢您的解释,但我可能会为此创建一个商店,而不是使用useRef
猜你喜欢
  • 2022-08-19
  • 1970-01-01
  • 2020-08-09
  • 1970-01-01
  • 1970-01-01
  • 2019-07-27
  • 1970-01-01
  • 1970-01-01
  • 2019-08-03
相关资源
最近更新 更多