简体   繁体   English

React/React Context API:使用 useEffect() hook 时等待上下文值

[英]React/React Context API: Wait for context values when using useEffect() hook

I am developing a web app using React and here is what I am trying to do:我正在使用 React 开发 web 应用程序,这就是我想要做的:

  1. In the highest-order component, check whether the user is logged in and if logged in, update 'userinfo' Context value.在最高阶组件中,检查用户是否已登录,如果已登录,则更新 'userinfo' 上下文值。
  2. In Profile.js, get the 'userinfo' Context value.在 Profile.js 中,获取 'userinfo' 上下文值。
  3. Check whether 'userinfo' is null or not, and call different APIs accordingly.检查'userinfo'是否为null,并相应调用不同的API。

I wrote the below code.我写了下面的代码。 The problem is that there is apparently a time lag for the userinfo context value to be delivered to the component.问题在于,将 userinfo 上下文值传递给组件显然存在时间滞后。 So when using useEffect() hook, Profile.js will render twice when userinfo is not null.所以当使用 useEffect() hook 时,当 userinfo 不是 null 时 Profile.js 会渲染两次。

Is there a way to fix this code so that it waits for 'userinfo' variable, and then call relevant APIs accordingly, not before?有没有办法修复此代码,使其等待“userinfo”变量,然后相应地调用相关 API,而不是之前?

Below is the code.下面是代码。 Any advice?有什么建议吗? Thanks a lot in advance!提前非常感谢!

import React, {useEffect, useContext} from 'react';
import Userinfo from "../context/Userinfo";


function Profile(props) {

   const {userinfo, setuserinfo}=useContext(Userinfo);

   useEffect(()=>{      
       ((userinfo==null)?
       /*API call A (When user is not logged in) */ :
       /*API call B (When user is logged in) */
       )},[userinfo])  

   return (
       (userinfo==null)?
       /*Elements to render when user is not logged in) */ :
       /*Elements to render when user is  logged in) */
   );
}

export default Profile;

The best solution here is to add a loading state in the context provider which is reset once the value is updated.这里最好的解决方案是在上下文提供程序中添加加载 state,一旦值更新,该提供程序就会重置。

function Profile(props) {

   const {userinfo, loading, setuserinfo}=useContext(Userinfo);

   useEffect(()=>{      
       if(!loading) {
            ((userinfo==null)?
             /*API call A (When user is not logged in) */ :
            /*API call B (When user is logged in) */
            )
       }
    )},[loading, userinfo])  

   if(loading) return <Loader />
   return (
       (userinfo==null)?
       /*Elements to render when user is not logged in) */ :
       /*Elements to render when user is  logged in) */
   );
}

I have this problem today, I like what Shubham does.我今天遇到了这个问题,我喜欢 Shubham 的做法。 But the way I solve it is just getting the userinfo from the previous component and pass it to this profile component.但是我解决它的方法只是从前一个组件中获取userinfo并将其传递给这个配置文件组件。

However, make sure you render the Profile component like this so that you can make sure the userinfo exists:但是,请确保像这样呈现Profile组件,以便确保userinfo存在:

function ParentComponent(){
 // do sth to get the userinfo here
return(
  <ParentComponent>
     {userinfo? <Profile userinfo={userinfo} /> : null}       
 <ParentComponent/>
)
}

Lets assume you are setting up a context like below:假设您正在设置如下上下文:

import React from 'react';
const AuthContext = React.createContext({
    userInfo: null,
    isLoggedIn: false,
    loading: true,
    setUser: () => {} 
});

export default AuthContext;

And you are setting up your Global Provider like this:您正在像这样设置您的全球提供商:

import React from 'react';
import  AuthContext  from './AuthContext'; // path to the context

export default class GlobalUserContext extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            userInfo: null,
            isLoggedIn: false,
            loading: true
            }
    }

    componentDidMount(){
        ( async() => {
            const currentUser = await getUser(); // say you are trying to log user in
            if(currentUser){
                this.setState({
                    userinfo: currentUser,
                    isLoggedIn: true,
                    loading: false
                });  
            }

        } )();
    }
    
    setUser = (user, check) => {
        this.setState({userInfo: user, isLoggedIn: check});
    };
    
    render(){
        return (
            <AuthContext.Provider 
            value={{
                user: this.state.user,
                setUser: this.setUser,
                isLoggedIn: this.state.isLoggedIn,
                loading: this.state.loading
            }}>
            {this.props.children} 
            </AuthContext.Provider>
        );
    }

}

Then in your functional component using useEffect ,you can do something like this:然后在使用useEffect的功能组件中,您可以执行以下操作:

import React, { useContext, useEffect} from 'react';
import AuthContext                     from '../../contexts/AuthContext'; // your content path

export const MyComponent = () => {
const {userInfo, isLoggedIn, loading} = useContext(AuthContext);
useEffect(() => {
// here you can now ask if the user data is still loading like so:
if(!loading){
// do something 
// UserInfo is available
}
}, [userInfo, loading]);
return (
<View>
{anything}
</View>
);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM