为啥当上下文值更新时我的上下文没有更新?

Posted

技术标签:

【中文标题】为啥当上下文值更新时我的上下文没有更新?【英文标题】:why my context doesn't update when the context value updates?为什么当上下文值更新时我的上下文没有更新? 【发布时间】:2020-11-25 14:48:44 【问题描述】:

所以我在我的 Gatsby 应用程序(基本上是用 React 编写)中使用 React 的上下文 API 来处理用户身份验证。我有两个使用该上下文的组件:dashboardnavBar。当我尝试登录和注销时,我的navBar 的行为与我的userContext 不同,但我的dashboard 不会响应。是否与结构有关,例如navBarlayout 的直接“孩子”,但dashboard 不是?我认为不是,毕竟,这就是为什么我使用 contextAPI 然后只是传递一个普通的道具。

代码如下:

//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,然后更新它,所以@987654341 @也知道,但dashboard 不知道。是关于re-render 的吗?谢谢!

【问题讨论】:

为什么要使用两个上下文?你可以把它们结合起来。我也从来没有看到你重复使用SetUserContext 你需要调用setUser 来触发渲染 我尝试将它们结合起来,如果您关注my example,它应该可以工作:) 你必须调用你的 setter 来更新你的上下文状态。 @Stutje 谢谢!我使用两种不同上下文的原因是它可以防止过多的重新渲染。但是感谢您编写代码笔 :) 这只是代码的一部分,我会在其他地方使用 SetUserContext,而在monitorAuth 中使用 setUser 来设置用户的值 @JULIENPICARD 我做到了。它只是代码的一部分,我会在其他地方使用 SetUserContext,setUsermonitorAuth 中用于设置用户的值 【参考方案1】:

它不起作用的原因是您的 &lt;Dashboard&gt; 组件不是上下文提供者的子组件。如果你使用 React devtools,你会看到组件树看起来像

<Dashboard>
  <Layout>
    <UserStateContext.Provider>
      <SetUserContext.Provider>
        ...
      </SetUserContext.Provider> 
    </UserStateContext.Provider> 
  </Layout>
</Dashboard>

当上下文值改变时,它会在其子树中查找useContext 的组件。但是,Dashboard 不是孩子,是父母!

如果你想遵循这种模式,一个解决方案可能是创建一个Dashboard 的父组件并将上下文放在那里。

【讨论】:

以上是关于为啥当上下文值更新时我的上下文没有更新?的主要内容,如果未能解决你的问题,请参考以下文章

当提供者组件父状态发生变化时,为啥不能更新子组件中的值(带有反应上下文)?

为啥当我使用箭头函数 onClick 时我的变量未定义?

为啥当我使用 React 钩子和 React 上下文添加新帖子时,我的状态会替换我的帖子

反应上下文对象似乎没有再次正确更新[重复]

当 ref 的值发生变化时,Vue 不会更新模板 Vue 3

为啥当我调用 UpdateData(FALSE) 时我的对话框没有立即更新?