如何使用带有钩子的上下文进行身份验证?

时间:2020-06-13 23:09:07

标签: reactjs react-hooks react-context

我正在尝试使用context处理我的应用程序中的身份验证。我遇到了问题,因为我试图在useContext之外调用Context.Provider,所以我将逻辑移到了提供程序的子组件。

现在,我在子组件中调用TypeError: Object is not iterable (cannot read property Symbol(Symbol.iterator))时收到一条错误消息useContext。从上下文或其他内容获取值真的是问题吗?

app.js

import AuthContextProvider from "./components/context/authContext";
import RegisterRoutes from "./components/routing/registerRoutes";

function App() {
   return (
      <AuthContextProvider>
          <Route
            exact
            path="/register"
            render={(props) => (
              <RegisterRoutes {...props} />
            )}
          />
      </AuthContextProvider>
   )
}

在我的authContext.js

import React, { useState, useEffect, createContext } from "react";

export const AuthContext = createContext();

const AuthContextProvider = (props) => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const setAuth = (boolean) => {
    setIsAuthenticated(boolean);
  };

//Auth API logic here//
  const apiOptions = {
    url: "users/is-verified",
    method: "GET",
    headers: {
      token: localStorage.token,
    },
  };

  async function isAuth() {
    axios(apiOptions)
      .then((response) => {
        const resData = response.data;
        resData === true ? setIsAuthenticated(true) : setIsAuthenticated(false);
      })
      .catch((error) => {
        console.log(error.response);
      });
  }

  useEffect(() => {
    isAuth();
  }, []);

  return (
    <AuthContext.Provider
      value={[isAuthenticated, setIsAuthenticated, setAuth]}
    >
      {props.children}
    </AuthContext.Provider>
  );
};

export default AuthContextProvider;

在我的registerRoutes.js

import React, { useContext } from "react";
import { Redirect } from "react-router-dom";
import Register from "../pages/register";
import AuthContext from "../context/authContext";

function RegisterRoutes(props) {
  const [isAuthenticated, setAuth] = useContext(AuthContext);

  return !isAuthenticated ? (
    <Register {...props} setAuth={setAuth} />
  ) : (
    <Redirect to="/login" />
  );
}

export default RegisterRoutes;

2 个答案:

答案 0 :(得分:1)

我认为这会对您有所帮助。我在上下文中访问数据的解决方案是创建一个自定义钩子。

//localState.js

import { createContext, useState, useContext } from 'react'

const LocalStateContext = createContext()

const LocalStateProvider = LocalStateContext.Provider

function LocalState({children}) {
  const [someState, setSomeState] = useState('')
  const defaultValues = {
    someState, setSomeState
  }
  
  return <LocalStateProvider value={defaultValues}>
            {children}
         </LocalStateProvider>
}

function useLocalState() {
  const all = useContext(LocalStateContext)
  return all
}

export {LocalState, LocalStateContext, useLocalState}

使用此代码,您可以将整个应用程序包装在LocalState组件中,并使用新的useLocalState挂钩访问上下文值。例如

import { useLocalState} from './localstate'

const SomeComponent = () => {
  const { someState } = useLocalState()
  
  return (
    ///...whatever you want
  )
}

export default SomeComponent
我认为您的问题可能是您已将默认值放在value对象内部的数组中。

答案 1 :(得分:1)

如错误所述,Context.Provider中的authContext.js不可迭代:

<AuthContext.Provider value={[isAuthenticated, setIsAuthenticated, setAuth]}>

传递给提供者的值必须是一个可迭代的值,在这种情况下,它是一个有效的JSON对象,而不是您提供的数组。因此,我们将其更改为:

<AuthContext.Provider value={{isAuthenticated, setIsAuthenticated, setAuth}}>

然后,您更改registerRoutes.js中的引用以正确使用新结构:

const [isAuthenticated, setAuth] = useContext(AuthContext);

成为

const { isAuthenticated, setAuth } = useContext(AuthContext);

Voila!您的Context.Provider值是可迭代的,您可以在应用程序中使用它。