使用useCallback挂钩记住API响应

时间:2020-09-08 14:31:47

标签: javascript reactjs react-hooks

单击按钮时,我需要在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的链接。

2 个答案:

答案 0 :(得分:2)

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;

答案 1 :(得分:1)

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;
}, []);

Edit cranky-silence-rdyxx