reactjs React应用重新渲染并使用axios无限获取数据

klh5stk1  于 2023-03-22  发布在  React
关注(0)|答案(4)|浏览(192)

我是一个自学成才的开发者,几乎完全是原生iOS应用。(由Firebase托管)。他来自乌克兰,突然不得不停下来,所以我接手完成了它。正因为如此,我一直无法传统地学习React/HTTPS/axios/Node.js,即以缓慢的速度学习教程,练习,虽然几个月前,我能够完成它,一切都很好。然而,在过去的几周里,我不得不重组我的整个架构,包括创建一个新的GCP项目,一个新的Firebase项目,新的git仓库等。其中包括所有的重新配置,除了一些代码优化和数据模型调整。正是在这个重组的某个时候,我的问题出现了。我提到这一切是为了指出**A)**我一直非常依赖他的原创作品,特别是在设置Firebase Hosting方面,**B)**我不确定问题出在哪里。我90%确定是React,但这很奇怪,因为两个月前完成异步网络调用时,我并没有对它做任何更改,它按预期工作。
无论如何,在出现时,Web应用程序请求将哪个视图呈现给客户端,这是NotFoundViewReviewUserViewUserProfileView,由后端给定userId确定。问题是当显示UserProfileView时,某些东西导致此视图无限重新渲染。首先,不超过两秒,它正确显示此视图,我认为这与useEffect和/或useState React钩子有关,尽管我不确定是在哪个视图中。
任何帮助都非常感谢,谢谢。

export enum ViewState { 
    UserProfile = 'UserProfile',
    ReviewForm = 'ReviewForm',
    NotFound = 'NotFound'
}

....................................................

export class ApiHandler { 
    // Returns a ViewState enum case for main view routing
    public static requestViewState(id: string): Promise<AxiosResponse<ViewState>> { 
        console.log('REQUESTING VIEW STATE')
        return axios.get(`${API_URL}/user/${id}/view-state`)
    }

    // Returns the requested user's profile data + other info
    public static requestUserData(id: string): Promise<AxiosResponse<UserData>> { 
        console.log('REQUESTING USER DATA')
        return axios.get(`${API_URL}/user/${id}`)
    }

    // More API calls ...
}

....................................................

export function RoutingView(props: RouteComponentProps<RoutingViewProps>) { 
    const userId = props.match.params.id
    const [viewState, setViewState] = useState<ViewState>()
    const [showError, setShowError] = useState<boolean>()
    const [showLoader, setShowLoader] = useState<boolean>(true)

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

    if (showLoader) { 
        return <PageLoader />
    }

    if (showError) { 
        return <FailedToLoad />
    }

    switch (viewState) { 
        case ViewState.UserProfile:
            return <UserProfileView id={userId} />
        case ViewState.ReviewForm:
            return <ReviewUserView id={userId} />
        default:
            return <NotFoundView />
    }

    async function loadViewState(): Promise<void> { 
        setShowLoader(true)
        try { 
            const viewStateData = await ApiHandler.requestViewState(userId)
            setViewState(viewStateData.data)
        } catch (error) { 
            console.log(error)
            setShowError(true)
        }
        setShowLoader(false)
    }
}

....................................................

export default function UserProfileView(props: UserProfileProps) { 
    console.log('INITIALIZED USERPROFILEVIEW')
    const userId = props.id
    const [userData, setUserData] = useState<UserData>()
    const [showLoader, setShowLoader] = useState<boolean>(false)
    const [service, setService] = useState<Service | null>()
    const [loadFailed, setLoadFailed] = useState<boolean>()

    useEffect(() => {
        if (userData?.user) { 
            const user = userData?.user
            document.title = `${user?.firstName} ${user?.lastName}`
        }
    }, [userData])

    useEffect(() => { 
        loadUserData()
    }, [userData])

    if (loadFailed) { 
        return <FailedToLoad />
    }

    return <div>
        {showLoader ? <PageLoader/> : ''}

        { 
            userData?.user && <div className={service ? styles.Hidden : ''}>
                <UserInfo 
                    user={userData?.user}
                    services={userData?.services}
                    selectedService={(service) => setService(service)}
                    submitted={userData?.hasSubmitted}
                />
            </div>
        }

    // More view components ...

    </div>

    async function loadUserData(): Promise<void> { 
        setShowLoader(true)
        try {
            const res = await ApiHandler.requestUserData(userId)
            setUserData(res.data as UserData)
        } catch (error) { 
            console.log(error)
            setLoadFailed(true)
        }
        setShowLoader(false)
    }
}

当在本地调试时,这是控制台快速输出的内容。重复的模式可能表明了一些东西,尽管我不知道是什么。**注意:**为了简单起见,我在这篇文章中重命名了一些东西,ReferralRequest.view实际上是UserProfileView

edqdpe6u

edqdpe6u1#

而是这样做:

//After every rendering ONLY IF `prop` or `state` changes in this case `userDate always change`
useEffect(() => { 
 loadUserData()
}, [userData])

执行以下操作:

//Runs ONCE after initial rendering
useEffect(() => { 
 loadUserData()
}, [])

要说明原因,您应该知道useEffect的dependencies参数(callback,dependencies)。
这里使用的不同情况
1-)未提供依赖:
副作用在每次渲染之后运行。

示例:

useEffect(() => {
    // Runs after EVERY rendering
  });

2-)**一个空数组[]:**这是你应该做的。
副作用在初始渲染后运行一次。

示例:

useEffect(() => {
    // Runs ONCE after initial rendering
  }, []);

3-)**有props或state值:**这是你的问题。
副作用仅在任何dependency值更改时运行。

示例:

useEffect(() => {
    // Runs ONCE after initial rendering
    // and after every rendering ONLY IF `prop` or `state` changes
  }, [prop, state]);
wydwbb8l

wydwbb8l2#

更改代码

useEffect(() => { 
    loadUserData()
}, [userData])

useEffect(() => { 
    if (!userData) loadUserData()
}, [userData])

修复了无限获取,useEffect方法依赖于userData中的任何更改。每次获取都会更改该变量,从而导致无限循环。添加if null检查将停止另一次数据获取。

czq61nw1

czq61nw13#

这是因为这段代码

useEffect(() => { 
    loadUserData()
}, [userData])

问题是useEffect的第二个参数是效应所依赖的变量。
如果这些变量中的任何一个在useEffect的回调中被改变,那么它将被再次调用,通过加载这些数据生成一个无限循环,通过setUserData查看它们,数据被改变,loadUserData再次被调用,等等。

aij0ehis

aij0ehis4#

要解决无限循环,请更改以下代码:

useEffect(() => { 
    loadUserData()
}, [userData])

这段代码:

useEffect(() => { 
    loadUserData()
}, [setUserData])

不要将状态作为参数传入,而是传入设置状态的方法。

相关问题