почему мой контекст не обновляется при обновлении значения контекста? - PullRequest
0 голосов
/ 05 августа 2020

, поэтому я использую контекстный API React в моем приложении Gatsby (которое в основном написано на React) для проверки подлинности пользователя. У меня есть два компонента, которые используют этот контекст: dashboard и navBar. Когда я пытаюсь войти и выйти из системы, мой navBar будет вести себя иначе, чем мой userContext, но мой dashboard не будет отвечать. Связано ли это со структурой, например, navBar является прямым «потомком» layout, а 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 во всех трех компонентах, и когда я обновляю sh страницу:

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? Спасибо!

1 Ответ

1 голос
/ 06 августа 2020

Причина, по которой он не работает, заключается в том, что ваш компонент <Dashboard> не является дочерним по отношению к поставщику контекста. Если вы используете React devtools, вы увидите, что дерево компонентов выглядит как

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

. Когда значение контекста изменяется, оно ищет в своем поддереве компоненты, которые useContext. Однако Dashboard не является дочерним, это родительский!

Если вы хотите следовать этому шаблону, решением может быть создание родительского компонента Dashboard и размещение в нем контекста.

...