为什么当上下文值更新时我的上下文不更新?
why my context doesn't update when the context value updates?
所以我在我的 Gatsby 应用程序(基本上是用 React 编写的)中使用 React 的上下文 API 来处理用户身份验证。我有两个使用该上下文的组件:dashboard
和 navBar
。当我尝试登录和注销时,我的 navBar
会根据我的 userContext
表现不同,但我的 dashboard
不会响应。是不是和结构有关,比如navBar
是直接“children”到layout
,但是dashboard
不是?我假设不是,毕竟,这就是为什么我使用 contextAPI
然后只传递一个普通的 prop.
代码如下:
//layout.js
import React, { useContext, useState, createContext } from "react"
import Navbar from "../components/navBar"
import {monitorAuth} from "../firebase/firebaseService"
export const UserStateContext = createContext(null)
export const SetUserContext = createContext()
const Layout = ({ children }) => {
const [user, setUser] = useState()
console.log(user)
monitorAuth(setUser)// everytime a layout component renders, it will grab a user if it is logged inthen setUser, then I will use it in the context
return (
<>
<UserStateContext.Provider value={user}>
<SetUserContext.Provider value={setUser}>
<div>
<SEO />
<Navbar />
<main>{children}</main>
</div>
</SetUserContext.Provider >
</UserStateContext.Provider>
</>
)
}
export default Layout
import React, { useState, useContext } from "react"
import AppBar from "@material-ui/core/AppBar"
import { signOut } from "../firebase/firebaseService"
import {UserStateContext} from "./layout"
export default function NavBar() {
const user = useContext(UserStateContext)
console.log(user) // when I log in/ log out, it will console.log the right user status, user/null
const renderMenu = () => {
return (
<>
{user? (
<>
<Button onClick={signOut}>Sign Out</Button>
<Button>My profile</Button>
</>)
:<Button>Sign In</Button> }
</>
)
}
return (
<AppBar position="static" className={classes.root}>
...
{renderMenu()}
...
</AppBar>
)
}
//dashboard.js
import React, { useContext } from 'react'
import Layout from '../components/layout'
import LoggedIn from '../components/dashboard/loggedIn'
import NotLoggedIn from '../components/dashboard/notLoggedIn'
import {UserStateContext} from "../components/layout"
const Dashboard = props => {
console.log("within dashboard")
const user = useContext(UserStateContext)
console.log(user)
const renderDashboard = () =>{
return (
<>
{user? <LoggedIn /> : <NotLoggedIn />}
</>
)
}
return(
<Layout>
{renderDashboard()}
</Layout>
)
}
export default Dashboard
还有一个线索,我 console.log user
在所有三个组件中以及当我刷新页面时:
within dashboard
dashboard.js:17 null
layout.js:15 undefined
navBar.jsx:54 undefined
layout.js:15 [user...]
navBar.jsx:54 [user...]
layout.js:15 [user...]
这意味着,起初 user
尚未设置,因此所有三个组件都将 user
记录为 undefined
,但稍后,layout
检测到 user
然后更新它,所以 navbar
也知道,但 dashboard
不知道。是关于 re-render
的吗?谢谢!
它不起作用的原因是因为您的 <Dashboard>
组件不是上下文提供程序的 child。如果你使用 React devtools,你会看到组件树看起来像
<Dashboard>
<Layout>
<UserStateContext.Provider>
<SetUserContext.Provider>
...
</SetUserContext.Provider>
</UserStateContext.Provider>
</Layout>
</Dashboard>
当上下文值发生变化时,它会在其子树中查找 useContext
的组件。但是,Dashboard
不是 child,而是 parent!
如果您想遵循此模式,解决方案可能是创建 Dashboard
的 parent 组件并将上下文放在那里。
所以我在我的 Gatsby 应用程序(基本上是用 React 编写的)中使用 React 的上下文 API 来处理用户身份验证。我有两个使用该上下文的组件:dashboard
和 navBar
。当我尝试登录和注销时,我的 navBar
会根据我的 userContext
表现不同,但我的 dashboard
不会响应。是不是和结构有关,比如navBar
是直接“children”到layout
,但是dashboard
不是?我假设不是,毕竟,这就是为什么我使用 contextAPI
然后只传递一个普通的 prop.
代码如下:
//layout.js
import React, { useContext, useState, createContext } from "react"
import Navbar from "../components/navBar"
import {monitorAuth} from "../firebase/firebaseService"
export const UserStateContext = createContext(null)
export const SetUserContext = createContext()
const Layout = ({ children }) => {
const [user, setUser] = useState()
console.log(user)
monitorAuth(setUser)// everytime a layout component renders, it will grab a user if it is logged inthen setUser, then I will use it in the context
return (
<>
<UserStateContext.Provider value={user}>
<SetUserContext.Provider value={setUser}>
<div>
<SEO />
<Navbar />
<main>{children}</main>
</div>
</SetUserContext.Provider >
</UserStateContext.Provider>
</>
)
}
export default Layout
import React, { useState, useContext } from "react"
import AppBar from "@material-ui/core/AppBar"
import { signOut } from "../firebase/firebaseService"
import {UserStateContext} from "./layout"
export default function NavBar() {
const user = useContext(UserStateContext)
console.log(user) // when I log in/ log out, it will console.log the right user status, user/null
const renderMenu = () => {
return (
<>
{user? (
<>
<Button onClick={signOut}>Sign Out</Button>
<Button>My profile</Button>
</>)
:<Button>Sign In</Button> }
</>
)
}
return (
<AppBar position="static" className={classes.root}>
...
{renderMenu()}
...
</AppBar>
)
}
//dashboard.js
import React, { useContext } from 'react'
import Layout from '../components/layout'
import LoggedIn from '../components/dashboard/loggedIn'
import NotLoggedIn from '../components/dashboard/notLoggedIn'
import {UserStateContext} from "../components/layout"
const Dashboard = props => {
console.log("within dashboard")
const user = useContext(UserStateContext)
console.log(user)
const renderDashboard = () =>{
return (
<>
{user? <LoggedIn /> : <NotLoggedIn />}
</>
)
}
return(
<Layout>
{renderDashboard()}
</Layout>
)
}
export default Dashboard
还有一个线索,我 console.log user
在所有三个组件中以及当我刷新页面时:
within dashboard
dashboard.js:17 null
layout.js:15 undefined
navBar.jsx:54 undefined
layout.js:15 [user...]
navBar.jsx:54 [user...]
layout.js:15 [user...]
这意味着,起初 user
尚未设置,因此所有三个组件都将 user
记录为 undefined
,但稍后,layout
检测到 user
然后更新它,所以 navbar
也知道,但 dashboard
不知道。是关于 re-render
的吗?谢谢!
它不起作用的原因是因为您的 <Dashboard>
组件不是上下文提供程序的 child。如果你使用 React devtools,你会看到组件树看起来像
<Dashboard>
<Layout>
<UserStateContext.Provider>
<SetUserContext.Provider>
...
</SetUserContext.Provider>
</UserStateContext.Provider>
</Layout>
</Dashboard>
当上下文值发生变化时,它会在其子树中查找 useContext
的组件。但是,Dashboard
不是 child,而是 parent!
如果您想遵循此模式,解决方案可能是创建 Dashboard
的 parent 组件并将上下文放在那里。