admin管理员组文章数量:1318570
so I am using React's context API in my Gatsby app(which is written in React basically) to deal with user authentication. I have two ponents that use that context: dashboard
and navBar
. When I try to log in and log out, my navBar
will behave differently according to my userContext
, but my dashboard
won't respond. Is it something related to the structure, like navBar
is the direct "children" to layout
, but dashboard
is not? I assume not though, after all, that's why I use contextAPI
then just pass a normal prop.
Here are the codes:
//layout.js
import React, { useContext, useState, createContext } from "react"
import Navbar from "../ponents/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 ponent 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 '../ponents/layout'
import LoggedIn from '../ponents/dashboard/loggedIn'
import NotLoggedIn from '../ponents/dashboard/notLoggedIn'
import {UserStateContext} from "../ponents/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
One more clue, I console.log user
in all three ponents and when I refresh the page:
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...]
That means, at first, user
is not set yet, so all three ponents log the user
as undefined
, but later, layout
detect the user
and then updates it, so navbar
knows too, but dashboard
doesn't. Is it something about re-render
? Thanks!
so I am using React's context API in my Gatsby app(which is written in React basically) to deal with user authentication. I have two ponents that use that context: dashboard
and navBar
. When I try to log in and log out, my navBar
will behave differently according to my userContext
, but my dashboard
won't respond. Is it something related to the structure, like navBar
is the direct "children" to layout
, but dashboard
is not? I assume not though, after all, that's why I use contextAPI
then just pass a normal prop.
Here are the codes:
//layout.js
import React, { useContext, useState, createContext } from "react"
import Navbar from "../ponents/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 ponent 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 '../ponents/layout'
import LoggedIn from '../ponents/dashboard/loggedIn'
import NotLoggedIn from '../ponents/dashboard/notLoggedIn'
import {UserStateContext} from "../ponents/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
One more clue, I console.log user
in all three ponents and when I refresh the page:
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...]
That means, at first, user
is not set yet, so all three ponents log the user
as undefined
, but later, layout
detect the user
and then updates it, so navbar
knows too, but dashboard
doesn't. Is it something about re-render
? Thanks!
-
1
Why do you use two contexts for this? You can bine them. Also i never see u re-use
SetUserContext
you need to callsetUser
to trigger a render – Stutje Commented Aug 5, 2020 at 12:32 - 1 I gave it a try to bine them and it should work, if you follow my example :) – Stutje Commented Aug 5, 2020 at 12:43
- You have to call your setter in order to update your context state. – JULIEN PICARD Commented Aug 5, 2020 at 13:31
-
@Stutje Thank you! The reason I use two different contexts is that it prevents from too much re-render. But thanks for doing the code-pen :) It is just part of the codes, I would use the SetUserContext somewhere else, and setUser is used in
monitorAuth
to set the user's value – Yingqi Commented Aug 5, 2020 at 22:38 -
@JULIENPICARD I did. It is just part of the codes, I would use the SetUserContext somewhere else, and
setUser
is used inmonitorAuth
to set the user's value – Yingqi Commented Aug 5, 2020 at 22:40
1 Answer
Reset to default 8The reason it's not working is because your <Dashboard>
ponent is not a child of the context provider. If you use React devtools, you'll see the ponent tree looks like
<Dashboard>
<Layout>
<UserStateContext.Provider>
<SetUserContext.Provider>
...
</SetUserContext.Provider>
</UserStateContext.Provider>
</Layout>
</Dashboard>
When the context value changes, it looks for ponents in its subtree that useContext
. However, Dashboard
is not a child, it's the parent!
If you want to follow this pattern, a solution may be to create a parent ponent of Dashboard
and put the context there.
本文标签: javascriptwhy my context doesn39t update when the context value updatesStack Overflow
版权声明:本文标题:javascript - why my context doesn't update when the context value updates? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742047789a2417891.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论