立即反应上下文API更新状态

时间:2020-04-18 21:37:29

标签: javascript reactjs firebase firebase-authentication gatsby

我正在Gatsby设置中使用上下文api来跟踪称为userIsLoggedIn的状态。我正在使用Firebase进行身份验证。

这是我的上下文文件:

import { createContext } from "react"

export const AppContext = createContext(null)

这是我的AppWrapper组件:

import React, { useState, useEffect } from "react"
import firebase from "../../config/firebase"
import { AppContext } from "../../context/AppContext"

const AppWrapper = ({ children }: any) => {
  const [userIsLoggedIn, setUserIsLoggedIn] = useState(false)

  const authListener = () => {
    firebase.auth().onAuthStateChanged(user => {
      if (user && user.emailVerified) {
        setUserIsLoggedIn(true)
      } else {
        setUserIsLoggedIn(false)
      }
    })
  }

  useEffect(() => {
    authListener()
  }, [])

  return (
    <>
      <AppContext.Provider
        value={{
          userIsLoggedIn,
        }}
      >
        <main>{children}</main>
      </AppContext.Provider>
    </>
  )
}

export default AppWrapper

这是我的索引页面,我要在该页面上跟踪用户是否登录,以便我可以显示/隐藏某些内容:

import React, { useContext } from "react"
import { AppContext } from "../context/AppContext"

const IndexPage = () => {
  const app = useContext(AppContext)

  console.log("app", app)

  return (
    <>
      {app && app.userIsLoggedIn && (
        <>
          <h1>Hello dearest user</h1>
          <p>Welcome to your page.</p>
        </>
      )}
    </>
  )
}

export default IndexPage

当我第一次加载页面或重新加载页面时,console.log组件中IndexPage的结果如下:

app {userIsLoggedIn: false}
app {userIsLoggedIn: true}

这意味着我的页面正在重新呈现,并且我的内容在用户登录时隐藏/显示的内容之间闪烁。是否有办法避免这种情况并使状态更加即时?我愿意接受任何建议:)

1 个答案:

答案 0 :(得分:0)

好的,所以我发现了对我的具体情况有用的东西。我没有使用上下文api来保持应用程序状态(重新加载时将重置为默认值,因此状态之间会闪烁),如果用户与我的authListener函数一起登录,我将使用localStorage进行保存

这是我添加的auth util

// Firebase
import firebase from "../config/firebase"

export const isBrowser = () => typeof window !== "undefined"

export const getUser = () => {
  if (isBrowser()) {
    const user = window.localStorage.getItem("user")
    if (user !== null) {
      return JSON.parse(user)
    } else {
      return ""
    }
  }
}

export const setUser = (email: string | null) =>
  isBrowser() && window.localStorage.setItem("user", JSON.stringify(email))

export const isLoggedIn = () => {
  const user = getUser()
  return !!user
}

export const logout = () => {
  return new Promise(resolve => {
    firebase
      .auth()
      .signOut()
      .then(() => {
        setUser("")
        resolve()
      })
  })
}

在我的AppWrapper函数中,我的authListener函数如下所示:

import { setUser, logout } from "../../utils/auth"

const authListener = () => {
    firebase.auth().onAuthStateChanged(user => {
      if (user && user.emailVerified) {
        setUser(user.email)
      } else {
        logout()
      }
    })
  }

  useEffect(() => {
    authListener()
  })

在我的应用程序中的任何地方,我都可以使用isLoggedIn()实用程序来检查用户是否实际上已登录,而内容没有闪烁。

如果我手动删除或更改localStorage user,则当应用程序发生任何更改时,它会立即通过authListener函数进行刷新。