React - Firebase 身份验证和 useContext

React - Firebase authentication and useContext

我正在尝试找出创建全局状态变量的最佳方法,该变量将保存 firebase 身份验证用户 ID。 例如,下面的代码将检查用户是否已登录,如果成功则将他们发送到欢迎页面。

但我还需要在不同的文件上设置私有路由,我希望能够共享 getId 状态。我读到 useContext 可以做到这一点,但不确定如何实现它。请指教,谢谢

const [getId, setId] = useState("");

const login = async ( id ) => {
    return setId(id);
  };

firebase.auth().onAuthStateChanged((user) => {
    if (user) {
      login(user.uid).then(() => {
       
    history.push("/welcome");
        
      });
    } else {
     
      history.push("/");
     
    }
  });
const PrivateRoute = ({ getId, component: Component, ...rest }) => (
  <Route
    {...rest}
    component={(props) =>
      getId ? (
        <div>
         
          <Component {...props} />
        </div>
      ) : (
        <Redirect to="/" />
      )
    }
  />
);

我会给你 我的 示例来获得 Auth 上下文。以下是部分:

_app.js 文件:

import '../styles/globals.scss'
import { motion, AnimatePresence } from 'framer-motion'
import { useRouter } from 'next/router'
import Header from '../components/Header'
import Footer from '../components/Footer'
import { AuthProvider } from '../contexts/AuthContext'
import { CartProvider } from '../contexts/CartContext'
import { ThemeProvider } from '@material-ui/core'
import theme from '../styles/theme'


export default function App({ Component, pageProps }) {
  const router = useRouter()

  return(
    <AnimatePresence exitBeforeEnter>
      <CartProvider>
        <AuthProvider>
          <ThemeProvider theme={theme}>
            <Header />
            <motion.div key={router.pathname} className="main">
              <Component { ...pageProps } />
              <Footer />
            </motion.div>
          </ThemeProvider>
        </AuthProvider>
      </CartProvider>
    </AnimatePresence>
  )
}

重要的项目是 <AuthProvider> 组件。这就是包装上下文的地方。

AuthContent.js 文件:

import { createContext, useContext, useEffect, useState } from 'react'
import { auth } from '../firebase'

const AuthContext = createContext()

export function useAuth() {
  return useContext(AuthContext)
}

export function AuthProvider({ children }) {
  const [currentUser, setCurrentUser] = useState()
  const [loading, setLoading] = useState(true)

  function login(email, password) {
    return auth.signInWithEmailAndPassword(email, password)
  }

  function signOut() {
    return auth.signOut();
  }

  function signUp(email, password) {
    return auth.createUserWithEmailAndPassword(email, password)
  }

  function getUser() {
    return auth.currentUser
  }

  function isAdmin() {
    return auth.currentUser.getIdTokenResult()
    .then((idTokenResult) => {
      if (!!idTokenResult.claims.admin) {
        return true
      } else {
        return false
      }
    })
  }

  function isEditor() {

  }

  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged(user => {
      setCurrentUser(user)
      setLoading(false)
    })

    return unsubscribe
  }, [])

  const value = {
    currentUser,
    getUser,
    login,
    signOut,
    signUp
  }

  return (
    <AuthContext.Provider value={value}>
      { !loading && children }
    </AuthContext.Provider>
  )

}

这是存储和访问状态的地方,包括所有助手(注册、注销、登录等)。

使用方法:

import { Button, Card, CardHeader, CardContent, Link, TextField, Typography } from '@material-ui/core'
import { motion } from 'framer-motion'
import { useRef, useState } from 'react'
import { useAuth } from '../contexts/AuthContext'
import { useRouter } from 'next/router'

export default function SignupForm() {

  const router = useRouter()
  const { signUp } = useAuth()
  const [state, setState] = useState({
    email: "",
    password: "",
    passwordConfirm: ""
  })
  const [error, setError] = useState("")

  function handleForm(e) {
    setState({
      ...state,
      [e.target.name]: e.target.value
    })
  }

  async function handleSubmit(e) {
    if (state.password !== state.passwordConfim) {
      setError("Passwords do not match")
    }
    await signUp(state.email, state.password)
    .catch(err => console.log(JSON.stringify(err)) )
    router.push("/account")
  }

  return(
    <motion.div>
      <Card >
        <CardHeader title="Header" />
        <CardContent>
          <TextField label="email" name="email" variant="outlined" onChange={ handleForm } />
          <TextField label="password" name="password" type="password" variant="outlined" onChange={ handleForm } />
          <TextField label="Password Confirmation" name="passwordConfirm" type="password" variant="outlined" onChange={ handleForm } />
          {error && <Alert severity="error" variant="filled" >{error}</Alert>}
          <Button onClick={ handleSubmit }>
            <Typography variant="button">Sign Up</Typography>
          </Button>
        </CardContent>
      </Card>
    </motion.div>
  )
}

您从您的上下文中导入 { useAuth }(我通常将我的放在上下文文件夹中)然后您可以通过解构调用组件内部变量的实例(例如 const { currentUser, login } = useAuth()