【问题标题】:React - Firebase authentication and useContextReact - Firebase 身份验证和 useContext
【发布时间】:2021-06-23 17:25:05
【问题描述】:

我正在尝试找出创建全局状态变量的最佳方法,该变量将保存 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="/" />
      )
    }
  />
);

【问题讨论】:

    标签: reactjs firebase use-context


    【解决方案1】:

    我会给你一个我的例子来获得一个Auth Context。以下是部分:

    _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>
      )
    }
    

    重要的项目是&lt;AuthProvider&gt; 组件。这就是包装上下文的地方。

    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()

    【讨论】:

    • 谢谢你,这很有帮助:)
    • 如果您遇到任何问题,请告诉我! :)
    • 登录和注销方法效果很好。我如何将它与私人路线一起使用?我认为目前代码是在检查身​​份验证之前呈现的,因此私有路由不起作用。最好的检查方法是什么?
    • 取决于架构。他们必须登录,还是授权?您可以使用 currentUser.uid 访问用户对象上的 id
    猜你喜欢
    • 2017-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 2017-06-13
    相关资源
    最近更新 更多