为什么在React Native中呈现组件之前上下文变量不可用?

7eumitmz  于 2023-01-18  发布在  React
关注(0)|答案(1)|浏览(132)

在React Native应用中,我有一个Login组件,它将userId存储在应用上下文中。登录后,用户将转到Dashboard组件,在该组件中使用useContext钩子访问userId。从数据库中获取帖子时需要userId。在组件装载时,我使用useEffect钩子调用获取函数。
问题是当useEffect执行并调用函数时,userId是未定义的。但是,如果我重新呈现组件,那么我可以通过日志看到,现在已经定义了id,但是因为useEffect已经执行,所以我没有从服务器获取数据。我已经尝试使用setTimeOut来解决这个问题()方法,但同样是在定义id之前进行提取。
最让我感到奇怪的是,在 Jmeter 板组件中,我按照相同的步骤从上下文访问令牌,这个令牌立即可用。
下面,我给你看我的代码和应用程序的日志:

This is the Context file
//AuthContext.tsx
import { createContext, useState } from "react";
import { AuthUser } from "../types/AuthUser";

type AuthContextProviderProps = {
    children: React.ReactNode
}

type AuthContextType= {
    
    isAuthenticated : boolean
    setIsAuthenticated : React.Dispatch<React.SetStateAction<boolean>>
    token : string
    setToken : React.Dispatch<React.SetStateAction<string>>
    userId : string
    setUserId : React.Dispatch<React.SetStateAction<string>>
    userName : string
    setUserName : React.Dispatch<React.SetStateAction<string>>
    
}

export const AuthContext = createContext({} as AuthContextType)

export const AuthContextProvider = ({children}: AuthContextProviderProps)=>{
   
    const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false)
    const [token, setToken] = useState<string>('')
    const [userId, setUserId] = useState<string>('')
    const [userName, setUserName] = useState<string>('')
    //const [authUser, setAuthUser] = useState<AuthUser>({userId:'', userName:''})
    return(
        <AuthContext.Provider  value={{isAuthenticated, setIsAuthenticated,token, setToken, userId,setUserId,userName,setUserName}}>
        {children}
        </AuthContext.Provider>
    )
}

在Login屏幕中,我将userId和token存储在Context中

const loginUser = async(): Promise<ISuccessFullResponse | boolean>=>{

    try {
        
        const body = {email, password}
        const url = REMOTE_SERVER+'/authentication/loginUser'
        console.log(url)
        const response = await fetch(url,{
        method : 'POST',
        headers:{'content-type':'application/json'},
        body : JSON.stringify(body)

    })
    
    console.log(loggedUser)
    const id = loggedUser.data.user._id
    const name = loggedUser.data.user.userName
    setToken(loggedUser.data.token)
    setUserId(id)
    setUserName(name)
    return loggedUser
    } catch (error) {
        console.log(error)
        }
        
        return false
    }
    
}

登录后,将重定向到 Jmeter 板。“”“const Jmeter 板:ReactFC =(支持)=〉{

//interfaces
interface IPost{
    contentString : string
    urls : string[]
}
//global state
const authContext = useContext(AuthContext)
const token = authContext.token
console.log('token in dashboard', token)
const id = authContext.userId
console.log('id in dashboard', id)


const profilePicContext = useContext(ProfilePicContext)
const setProfilePic = profilePicContext.setProfilePic

//local state
const [arrayOfPosts, setArrayOfPosts] = useState<IPost[]>([])
const [status, setStatus] = useState<string>('')
const [errMsg, setErrMsg] = useState<string>("")

//props
const navigation = props.navigation

//function definitions
const getProfilePicture = async():Promise<boolean>=>{
   
    try {
        const response = await fetch(REMOTE_SERVER+'/dashboard/downloadProfilePicture', {
            headers : {token}

        })
        const parseResponse = await response.json()
        if(parseResponse.data){
            setProfilePic(parseResponse.data)
        }
        
    } catch (error) {
        console.log(error)
        if(error instanceof Error){
            console.log('this is the error',error)
            return false
        }
    }
    return true 
}

const getPostsFromFollowingUsers = async():Promise<boolean>=>{
    setStatus('LOADING')
    try {
      
           
           console.log('inside function id', id)
           
            const response = await fetch(REMOTE_SERVER+`/userPost/getPostsFromFollowingUsers/${id}`, {
                method : 'GET',
                headers : {'Content-Type': 'application/json'}
                })
            const parseResponse = await response.text()
            console.log('this is the parseresponse',parseResponse)
            const responseObject = JSON.parse(parseResponse)
       
            if(responseObject.data){
                setArrayOfPosts(responseObject.data)
            }      
    } catch (error) {
        console.log('this is the error',error)
        setStatus('ERROR')
        if(error instanceof Error){
           setErrMsg(error.message)
            
        }
        
    }    
    return true
}

 useEffect(()=>{
    getProfilePicture()
}, [])  
useEffect(()=>{
    getPostsFromFollowingUsers()
}, []) 
  

return(

'''如您所见,常量标记的存储和访问方式与userId相同,但该标记在 Jmeter 板中可访问,并在getProfilePicture()中成功使用。另一方面,userId最初未定义,在调用getPostFromFollowingUsers()后变为已定义。以下是日志:

token in dashboard eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiNjJkMTg1YjI2NTliZDEzMjlhNDVjMzBkIiwiaWF0IjoxNjczODAzMDQ5LCJleHAiOjE2NzM4MzkwNDl9.HdJn0YAfi-yM9wPZMek6zmw4SUE2TsR_AzUOK06MeBg
 LOG  id in dashboard
 LOG  name in dashboard
 LOG  inside function id
 LOG  token in dashboard eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiNjJkMTg1YjI2NTliZDEzMjlhNDVjMzBkIiwiaWF0IjoxNjczODAzMDQ5LCJleHAiOjE2NzM4MzkwNDl9.HdJn0YAfi-yM9wPZMek6zmw4SUE2TsR_AzUOK06MeBg
 LOG  id in dashboard 62d185b2659bd1329a45c30d
 LOG  name in dashboard
 LOG  token in dashboard eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiNjJkMTg1YjI2NTliZDEzMjlhNDVjMzBkIiwiaWF0IjoxNjczODAzMDQ5LCJleHAiOjE2NzM4MzkwNDl9.HdJn0YAfi-yM9wPZMek6zmw4SUE2TsR_AzUOK06MeBg
 LOG  id in dashboard 62d185b2659bd1329a45c30d
 LOG  name in dashboard Joaquin
 LOG  token in dashboard eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiNjJkMTg1YjI2NTliZDEzMjlhNDVjMzBkIiwiaWF0IjoxNjczODAzMDQ5LCJleHAiOjE2NzM4MzkwNDl9.HdJn0YAfi-yM9wPZMek6zmw4SUE2TsR_AzUOK06MeBg
 LOG  id in dashboard 62d185b2659bd1329a45c30d
 LOG  name in dashboard Joaquin
 LOG  this is the parseresponse <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /userPost/getPostsFromFollowingUsers/</pre>
</body>
</html>
 LOG  this is the error [SyntaxError: JSON Parse error: Unrecognized token '<']

当然,路由需要一个参数才能工作,这就是为什么我得到这个错误。现在id I type a space in Visual Studio Code useEffect被再次调用,现在userId被定义,这样就可以执行提取并从服务器检索数据。如果有人分享了如何解决这个问题的想法,我将不胜感激。

yr9zkbsy

yr9zkbsy1#

添加一个加载状态到你的组件,当你获取数据时设置为true,然后当数据被获取时设置为false,当活动加载器加载时显示它,这可能会解决你的问题。

const { userId } = useContext(AppContext);

useEffect(() => {
    if (userId) {
        fetchData(userId).then(data => {
            setIsLoading(false);
        });
    }
}, [userId]);

相关问题