React:如何防止 Hook 在每次重新渲染时被调用?

3

我对React和React钩子有些陌生。我有一个组件,调用通信钩子,在其中使用AXIOS调用API,然后将JSON响应反馈给组件。问题是该组件连续调用钩子六次,其中四次返回未定义数据,另外两次返回预期的JSON数据(这两次都相同)。

我快速使用console.log进行了确认,以确定它确实是组件调用了多个钩子还是发生在钩子内部,结果发现是组件调用了多个钩子。

我应该如何才能仅在需要时调用一次钩子,而不像现在这样多次调用呢?以下是相关部分(不包括小组件中的其余代码,因为这与问题无关):

export default function TestWidget() {

//Fetch data from communicator
console.log("called");
const getJSONData = useCommunicatorAPI('https://jsonplaceholder.typicode.com/todos/1');

//Breakdown passed data
const {lastName, alertList, warningList} = getJSONData;

return (          
            <h1 id="welcomeTitle">Welcome {lastName}!</h1>

     );

}


export const useCommunicatorAPI = (requestAPI, requestData) => {

const [{ data, loading, error }, refetch] = useAxios('https://jsonplaceholder.typicode.com/todos/1', []);
console.log("data in Communicator:", data);

   return {data};
 }

我们还需要尽可能多的重现问题的etc......。请参见[mre]。 - zero298
我的意思是,我只是添加了一点点内容,但它并不是很相关。这只是一个将传递的数据分解为变量,然后进行渲染返回的部分。这就是整个组件,非常简单。 - user13709264
1
你能展示一下 useCommunicatorAPI 吗?那是第三方库吗? - zero298
不是的。只是我写了一个包含axios-hooks调用的钩子。我也添加了它,没有什么特别的。 - user13709264
3个回答

1
我会使用useEffect钩子在挂载时以及请求的任何依赖项更改时执行此操作(例如,如果URL更改)。
以下是您需要查看的内容:useEffect 以下是示例代码:
const [jsonData, setJsonData] = React.useState({})
const url = ...whatver the url is
React.useEffect(() => {
  const doFetch = async () => {
    const jsonData = await useAxios(url, []);;
    setJsonData(jsonData)
  }
  doFetch();
}, [url])
...use jsonData from the useState

通过上面的示例,获取(fetch)将在挂载时和url更改时发生。


2
我曾尝试使用useEffect,但编译错误提示我不能在其中调用hook,这真的很奇怪。至于使用URL作为检查,是行不通的,因为它们实际上将被封装在Communicator中。组件(调用hook的任何组件)只需告诉它想从哪个API获取数据。那我得想出其他办法了。 - user13709264
我使用你上面的代码尝试了一次,并且得到了与上次相同的编译错误:React Hook“useCommunicatorAPI”在函数“doFetch”中被调用,但该函数既不是React函数组件也不是自定义React Hook函数。 - user13709264
在useEffect内部不能使用hooks。这个解决方案只是将功能从hook中移出到组件中。如果你想在10个不同的组件上执行这个请求,使用这个解决方案,你将不得不在每个组件中重新编写代码。这不是一个好的解决方案。 - undefined
更新以使axios调用不使用hook语言(use),这会令人困惑。它实际上不是一个hook,只是一个调用axios的函数。如果您想在10个不同的组件上执行此请求,只需使用自定义hook共享逻辑。示例是针对此组件而不是多个组件的,因此解决方案并不反映这一点。 - undefined

1
为什么不直接使用钩子?
export default function TestWidget() {
 const [{ data, loading, error }, refetch] = 
useAxios('https://jsonplaceholder.typicode.com/todos/1', []);

  return (<h1 id="welcomeTitle">Welcome {lastName}!</h1>);
}

空数组[]会在调用时触发一次钩子。

因为这个通信器钩子最终将被用于创建一个抽象层,调用组件会告诉它要从哪个外部API获取数据。我添加了空的[],试图减少在跟踪到调用组件之前的调用次数。 - user13709264

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接