我可以在 useEffect 中调用单独的函数吗?

IT技术 reactjs react-hooks
2021-05-01 08:20:05

我可以在 useEffect 中调用另一个单独的函数吗?

我正在调用 useEffect 中的另一个函数,但在保存文件后,它会自动将该函数添加到 useEffect 的数组参数中。

请参阅下面的代码以正确理解。

保存文件前:

useEffect(() => {
  getData()
  console.log("useEffect ran...");
}, [query]);

function getData() {
  fetch(`https://jsonplaceholder.typicode.com/${query}`)
  .then(response => response.json())
  .then(json => setData(json));
}

保存文件后:

useEffect(() => {
  getData();
  console.log("useEffect ran...");
}, [getData, query]);

function getData() {
  fetch(`https://jsonplaceholder.typicode.com/${query}`)
    .then(response => response.json())
    .then(json => setData(json));
}

它一次又一次地运行。

4个回答

TL; DR 使用 useCallback()


首先,让一个函数成为依赖是非常危险的。如果该函数导致状态更改,则随后的重新渲染将再次调用该函数(通过 useEffect)...并开始无限循环。

正如许多人在这里建议的那样,您可以做的一件事是在 useEffect() 方法本身内创建函数。

 useEffect(() => {
    function getData() {
      fetch(`https://jsonplaceholder.typicode.com/${query}`)
        .then(response => response.json())
        .then(json => setData(json));
      }
    }

    getData();
    console.log("useEffect ran...");
  }, [query]);
}

或者干脆

 useEffect(() => {
    (() => {
       fetch(`https://jsonplaceholder.typicode.com/${query}`)
      .then(response => response.json())
      .then(json => setData(json)
     )();
  }, [query]);
}

话虽如此,有时您仍然希望在 useEffect 之外为code-reuse声明函数这次您需要确保它不会在每次渲染期间重新创建。为此,您可以

  1. 在组件外声明函数——这迫使你将所有变量作为参数传递......这是一个痛苦

  2. 把它包在里面useMemo()useCallback()

这是一个例子

    const getData = useCallback(()=>{...}, []);

由于您getData在 React 组件中声明了该函数,它将在每次渲染时重新创建,因此效果的依赖关系在每次渲染时都会发生变化。这就是为什么在每次渲染上执行效果的原因。

为了防止这种情况,您应该getData在组件外部声明函数,然后传递查询。像这样:

function getData(query) {
  return fetch(`https://jsonplaceholder.typicode.com/${query}`)
    .then(response => response.json());
}

function YouComponent({ query }) {
  ...
  useEffect(() => {
    getData(query).then(setData);
    console.log("useEffect ran...");
  }, [query]);

  ...

PS:我不确定 eslint 插件在这样做时是否会自动将 getData 添加到依赖项中,但即使这样做也不会造成伤害。

接受的答案在某种程度上具有误导性。在组件内部定义函数显然会在每次渲染时重新创建。但这并不意味着在 useEffect 内部使用钩子时,它会在每个渲染中重新调用。

保存文件代码后的关键问题,即您正在监视 getData。当它在每次渲染时重新创建时,useEffect 将其作为更改接受,从而导致您在每次渲染上重新运行。简单的解决方法是不观看 getData。

但显然,正如接受的答案中所建议的那样。更好的做法是将组件外的函数分开,这样它就不会在每次渲染时重新创建。

坦率地说,如果我是你,我不会只为 fetch 定义函数:

useEffect(() => {
  fetch(`https://jsonplaceholder.typicode.com/${query}`)
    .then(response => response.json())
    .then(json => setData(json));
}, [query]); // only re-run on query change

如果将getData函数移动到 中useEffect,则不必将其作为依赖项包含在内,并且useEffect只会在query更改时运行