反应以编程方式调用钩子

时间:2019-10-27 23:37:02

标签: javascript reactjs react-hooks polling

https://codesandbox.io/s/react-hooks-usefetch-cniul

有关我的代码的简化版本,请参见上面的网址。

我希望能够在一定时间间隔内(基本上是轮询端点以获取数据)使用钩子从API提取数据。

我想要的是能够仅调用refetch之类的代码(如我在代码中作为注释所示),它实际上将再次调用fetchData并使用做出相应的反应。

解决此问题的最佳方法是什么?我能想到的唯一方法是在钩子中添加一个checker变量,该变量将是某种uuid(可能是Math.random()),将setChecker返回为refetch并将checker作为第二个useEffect参数添加到数组以控制重新渲染。因此,每当您调用refetch时,它都会调用setChecker来更新随机数(checker),然后函数再次运行。

显然这听起来很“ hacky”,一定有更好的方法-有想法吗?

4 个答案:

答案 0 :(得分:0)

如果您想进行持续的民意测验,我想您可以像这样将setInterval()移入钩子:

function useFetch() {
  const [data, setDataState] = useState(null);
  const [loading, setLoadingState] = useState(true);
  useEffect(() => {
    function fetchData() {
      setLoadingState(true);
      fetch(url)
        .then(j => j.json())
        .then(data => {
          setDataState(data);
          setLoadingState(false);
        });
    }

    const interval = setInterval(() => {
      fetchData();
    }, 5000);

    fetchData();

    return () => clearInterval(interval);
  }, []);

  return [
    {
      data,
      loading
    }
  ];
}

请记住包括return () => clearInterval(interval);,以便正确清理钩子。

答案 1 :(得分:0)

import React, { useEffect, useState, useCallback } from "react";
import ReactDOM from "react-dom";

const url = "https://api.etilbudsavis.dk/v2/dealerfront?country_id=DK";

function useFetch() {
  const [data, setDataState] = useState(null);
  const [loading, setLoadingState] = useState(true);
  const refetch = useCallback(() => {
    function fetchData() {
      console.log("fetch");
      setLoadingState(true);
      fetch(url)
        .then(j => j.json())
        .then(data => {
          setDataState(data);
          setLoadingState(false);
        });
    }
    fetchData();
  }, []);

  return [
    {
      data,
      loading
    },
    refetch
    // fetchData <- somehow return ability to call fetchData function...
  ];
}

function App() {
  const [
    { data, loading },
    refetch
    // refetch
  ] = useFetch();

  useEffect(() => {
    const id = setInterval(() => {
      // Use the refetch here...
      refetch();
    }, 5000);
    return () => {
      clearInterval(id);
    };
  }, [refetch]);

  if (loading) return <h1>Loading</h1>;
  return (
    <>
      <button onClick={refetch}>Refetch</button>
      <code style={{ display: "block" }}>
        <pre>{JSON.stringify(data[0], null, 2)}</pre>
      </code>
    </>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

答案 2 :(得分:0)

以下内容可能会起作用,需要对useFetch进行一些调整,但您仍然可以在其他地方正常调用它。

//maybe you can pass url as well so you can use
//  it with other components and urls
function useFetch(refresh) {
  //code removed
  useEffect(() => {
    //code removed
  }, [refresh]);
  //code removed
}

const [refresh, setRefresh] = useState({});
const [{ data, loading }] = useFetch(refresh);
useEffect(() => {
  const interval = setInterval(
    () => setRefresh({}), //forces re render
    5000
  );
  return () => clearInterval(interval); //clean up
});

答案 3 :(得分:0)

简单回答问题:

export default function App() {
  const [entities, setEntities] = useState();
  const [loading, setLoadingState] = useState(true);

  const getEntities = () => {
    setLoadingState(true);

    //Changet the URL with your own
    fetch("http://google.com", {
      method: "GET",
    })
      .then((data) => data.json())
      .then((resp) => {
        setEntities(resp);
        setLoadingState(false);
      });
  };

  useEffect(() => {
    const interval = setInterval(() => {
      getEntities();
    }, 5000);

    return () => clearInterval(interval);
  }, []);
}