即时反应上下文 api 更新状态

Posted

技术标签:

【中文标题】即时反应上下文 api 更新状态【英文标题】:React context api update state instantly 【发布时间】:2020-08-01 10:15:20 【问题描述】:

我在 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

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

app userIsLoggedIn: false
app userIsLoggedIn: true

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

【问题讨论】:

尝试改变 useEffect authListener 逻辑如this 【参考方案1】:

好的,我找到了对我的具体案例有帮助的方法。我没有使用上下文 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 函数会立即刷新它。

【讨论】:

以上是关于即时反应上下文 api 更新状态的主要内容,如果未能解决你的问题,请参考以下文章

反应上下文状态未更新

通过反应上下文 api 将子状态传递给父组件

React - 每当更新反应上下文中的状态时如何调用函数?

使用上下文和钩子更新未安装组件的状态 - 反应原生

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

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