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

rqqzpn5f  于 2023-04-05  发布在  React
关注(0)|答案(6)|浏览(117)

我可以在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));
}

它一次又一次地运行。

zed5wv10

zed5wv101#

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外声明函数,以便代码重用。这次你需要确保它不会在每次渲染时重新创建。为此,你可以选择
1.在组件外声明函数--这迫使您将所有变量作为参数传递……这很痛苦
1.将其 Package 在useMemo()useCallback()
这里有一个例子

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

li9yvcax2#

因为你在React组件中声明了getData函数,所以它会在每次渲染时重新创建,因此效果的依赖关系会在每次渲染时改变。这就是为什么效果会在每次渲染时执行的原因。
为了防止这种情况发生,您应该在组件外部声明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]);

  ...

P.S:我不确定eslint插件是否会在这样做时自动将getData添加到依赖项中,但即使这样做也不会有什么坏处。

mhd8tkvw

mhd8tkvw3#

公认的答案在某种程度上是误导性的。在组件内部定义函数显然会在每次渲染时重新创建。但这并不意味着当使用内部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
u4dcyp6a

u4dcyp6a4#

你也可以使用useRef来创建一个ref,并将函数定义放在那里,然后使用ref.current()调用它。即使是React也支持使用ref作为示例变量。
useRef返回一个可变的ref对象,其.current属性被初始化为传入的参数(initialValue)。返回的对象将在组件的整个生存期内持续存在。
然而,useRef()的用处远不止ref属性,它可以方便地保存任何可变值,就像在类中使用示例字段一样。

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

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

重要提示:

如果你想在这个方法中使用任何状态变量,那么你必须创建一个可变对象(就像另一个ref),它将包含state的最新值,就像你直接引用一个state变量一样,那么它将引用在方法创建时创建的旧值/默认值。要了解更多信息,你可以refer hereuseCallback方法也是如此。

zysjyyx4

zysjyyx45#

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

sh7euo9m

sh7euo9m6#

尝试将getData函数 Package 在useCallback钩子内,并将其放在组件外,这样,当getData被调用时,它将不会一直返回新函数,因此它将阻止组件重新呈现

相关问题