React hooks添加依赖项导致无限循环的问题?

奇诺比不珂
  • 1
新手上路,请多包涵
const routeMatch: match | null = useRouteMatch("/user/detail/:id"); 

const fetchData = useCallback(() => { Axios.get(`/api/admin/user/get?id=${routeMatch?.params.id}`)
.then((r) => 
{ setUserDetail(r.data.user); }); }
, [setUserDetail]);

useEffect(() => { fetchData(); }, [fetchData]);

此时eslint警告需要在fetchData的第二个参数中添加routeMatch的依赖,但是routerMatch在每一次渲染后都会引发再次渲染,于是产生无限循环 如何解决这个问题?

回复
阅读 1.1k
2 个回答

import { useCallback, useState, useEffect } from 'react'
import Axios from 'axios'

interface match {
    params: {
        [key: string]: string
    }
}

function useRouteMatch(url: string): match {
    return {
        params: {
            id: `100${url}`
        }
    }
}

function useTestHook() {
    const [, setUserDetail] = useState()
    const routeMatch: match | null = useRouteMatch("/user/detail/:id")

    const fetchData = useCallback(() => {
        Axios.get(`/api/admin/user/get?id=${routeMatch?.params.id}`)
            .then((r) => { setUserDetail(r.data.user) })
    }, [routeMatch])

    useEffect(() => { fetchData() }, [fetchData])
}

我简单补全了一下一个代码,我觉得吧,你这 setUserDetail 是useState闭包产生的,每一次都不一样,不应该把它作为依赖项,应该作为依赖项的是routeMatch把,不然每次渲染,useState生成新的setUserDetail函数,新的setUserDetail函数又触发fetchData去执行setUserDetail函数导致重新渲染一遍

测试后useRouteMatch是在每次渲染后都会被再次触发,但引起无限循环的是setUserDetail(r.data.user),因为r.data.user是对象,所以每次setUserDetail后,会认为数据发生变更,会再次渲染页面。

因为match被改变,所以fetch被再次执行,setUserDetail被再次执行,页面重新渲染,match被改变,无限循环。

如果set的数据是一个基础类型,就不会无限循环了。

可能的解决方法:

1.params.id写成useCallback的参数,而不是依赖,通过fetch(id)来调用。

id可以通过useParams来获取,这个不会渲染后再次触发。

id可以放在useState中,在match改变后set进去。

这样被依赖的是id不是match,渲染后不会被改变。

2.直接依赖useParams返回的id而不是matchiduseParams在重新渲染后不会再次被触发。

3.在fetch里自行对比数据,没更新则不set

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
你知道吗?

宣传栏