【问题标题】:React/Redux fetching data and conditionally render a component - too many re-rendersReact/Redux 获取数据并有条件地渲染组件 - 重新渲染太多
【发布时间】:2021-06-13 19:49:04
【问题描述】:

我想从我的后端获取数据,相应地更改“isLoggedIn”状态,从而有条件地渲染组件。我只是无法理解如何以组件不会呈现两次的方式构造它。

首先在我的 AuthForm 组件中,有一个登录功能。它设置了一个用于刷新 JWT 令牌的 httpOnly cookie,并直接在标头上设置了一个 JWT 令牌。

const login = async () => {
        try {
            const response = await axios.post(props.baseUrl + "/auth/login", {
                email,
                password,
            })

            axios.defaults.headers.common[
                "Authorization"
            ] = `Bearer ${response.data.token}`

            dispatch(toggleLogin(true))
        } catch ({ response }) {
            console.log(response)
        }
    }

因为我想显示游戏 UI 而不是 AuthForm,所以我正在调度 toggleLogin 操作。

在主组件中,我有一个 refreshToken 函数,它检查客户端是否有一个 httpOnly cookie,如果它有效则返回一个新的 JWT。这样用户在页面刷新时仍然登录。

const Tamagotchi = () => {
    const isLoggedIn = useSelector((state) => state.isLoggedIn)
    const dispatch = useDispatch()

    const refreshToken = async () => {
        try {
            const response = await axios.get(baseUrl + "/auth/refresh-token")

            axios.defaults.headers.common[
                "Authorization"
            ] = `Bearer ${response.data.token}`

            dispatch(toggleLogin(true))

            setTimeout(() => {
                refreshToken()
            }, response.data.expiresIn * 1000 - 500)
        } catch ({ response }) {
            if (response.status !== 201) {
                dispatch(toggleLogin(false))
                console.log("Not authorized")
            }
        }
    }

    useEffect(() => {
        refreshToken()
    })

    return (
        <TamagotchiWrapper>
            <TamagotchiView>
                {isLoggedIn ? <TamagotchiUI /> : <AuthForm />}
            </TamagotchiView>
        </TamagotchiWrapper>
    )
}

如果用户正在登录,或者正在刷新页面,Tamagotchi 组件会被渲染两次。由于isLoggedIn 发生了变化,因此状态发生了变化,因此它再次呈现并再次调用 useEffect 挂钩。 这个怎么办?

提前致谢。

【问题讨论】:

    标签: javascript reactjs redux react-redux


    【解决方案1】:

    尝试将refreshToken() 调用封装在useMemo 中,而不是useEffectuseEffect 在组件打印 JSX 之后起作用,而 useMemo 在它之前起作用。

    useMemo(() => {
      refreshToken()
    }, []);
    

    【讨论】:

    • 这样refershToken()函数在用户登录时不会被触发,我需要它触发它以在令牌过期之前刷新令牌!
    【解决方案2】:

    请提供空的依赖数组,这意味着仅在初始加载期间渲染。

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

    【讨论】:

    • 它给了我 ESLint 警告,在依赖数组中包含 refreshToken,这再次导致相同的行为。我还尝试将refreshToken() 函数包装在useCallback Hook 中,dispatch 作为其数组中的依赖项。这会导致登录时不会触发该功能。应该在 JWT 令牌过期后刷新它。
    • 如果您忽略 es lint 警告,它是否有效?否则,您可以尝试将其设为类组件并在componenetDidMount 生命周期方法中调用refreshToken,但为此您需要在导出组件之前使用connect
    • 它以某种方式工作。 Tamagotchi 组件只渲染一次,但我在成功登录时无法调用refreshToken() 函数。
    【解决方案3】:

    解决方案是将refreshToken 作为useEffect() 中的依赖项传递,并将refreshToken() 函数包装在useCallback Hook 中。

    然后将refreshToken() 函数传递给我的AuthForm 组件并在成功登录时调用它。

    这样,refreshToken 函数会在打开应用程序以验证用户身份时正确调用,并且在成功登录时能够刷新令牌。

    【讨论】:

    • 你能用你的代码更新答案吗?
    • 它告诉我必须等待至少 48 小时才能将自己的答案标记为解决方案。明天我会做出一个新的答案,因为我找到了一个更清洁的解决方案并会相应地标记它!
    猜你喜欢
    • 2020-11-27
    • 2018-03-24
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多