为了账号安全,请及时绑定邮箱和手机立即绑定

React自定义hook无限渲染

React自定义hook无限渲染

慕仙森 2023-09-28 15:41:59
我制作了一个自定义钩子,用于获取新闻 API 并返回用于加载、错误和数据的处理程序(受到 Apollo Client 的启发)。问题是,当使用它时,即使依赖项数组中的项目没有改变,它也会无限地自行触发。这就是我的实现方式:钩子:const useSearch = (query: string, sources: string[]) => {  const [response, setResponse] = useState<State>({    data: null,    loading: true,    error: null,  });  useEffect(() => {    newsapi      .getEverything({        q: query,        pageSize: 1,        sources: sources,      })      .then((data) => {        setResponse({ data, loading: false, error: null });      })      .catch((e) => {        setResponse({ data: null, loading: false, error: e });      });  }, [query, sources]);  return response;};用法:  const { loading, error, data } = useSearch("Donald", ["bbc-news"]);我超出了 API 的每日费率:我究竟做错了什么?
查看完整描述

1 回答

?
拉风的咖菲猫

TA贡献1995条经验 获得超2个赞

我提供了解决方案,@JacobSmit 在评论部分进行了解释。现在我只是把它们整理成一个更详细的答案,希望对后来者有所帮助。


解决方案

const useSearch = (query: string, sources: string[]) => {

  // ...

  useEffect(() => {

    // ...


    // FIX:

    // just apply the spread operator (...) to `sources`

    // to spread its elements into the dependency array of `useEffect`

  }, [query, ...sources]);


  return response;

};

解释

自useSearch定义挂钩传递[query, sources]到 的 dep 数组useEffect,其中 assources: string[]本身就是一个数组。这使得 dep 数组的形状为:


["query", ["source_1", "source_2", ..., "source_n"]]

看到 dep 数组的第二个元素是一个嵌套数组。useEffect然而,使用 dep 数组的方法是Object.is对其每个元素应用相等检查:


// pseudo code

function isDepArrayEqual(prevDepArray: any[], currDepArray: any[]) {

  return prevDepArray.every(

    (prevElement, index) => Object.is(prevElement, currDepArray[index])

  )

}

每次重新渲染时,钩子调用useSearch("Donald", ["bbc-news"])都会创建一个新的数组实例sources。这将使检查失败Object.is(prevSources, currSources),因为数组的相等性是通过它们的引用来比较的,而不是它们包含的值。


使用扩展运算符[query, ...sources],您可以将 dep 数组的形状转换为:


["query", "source_1", "source_2", ..., "source_n"]

关键区别不在于复制,而在于解压数组sources。


现在嵌套sources数组已解包,并且 dep 数组的每个元素只是字符串。对字符串的相等性检查是通过它们的值而不是引用进行比较,因此useEffect将认为 dep 数组不变。错误已修复。


查看完整回答
反对 回复 2023-09-28
  • 1 回答
  • 0 关注
  • 82 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信