【问题标题】:How to use context with hooks for authentication?如何使用带有钩子的上下文进行身份验证?
【发布时间】:2020-06-13 23:09:07
【问题描述】:

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

现在我收到一条错误消息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;

【问题讨论】:

    标签: reactjs react-hooks react-context


    【解决方案1】:

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

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

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

    【讨论】:

    • 这是有道理的,但现在我收到了来自registerRoutes.js 的错误TypeError: Cannot destructure property 'isAuthenticated' of 'Object(...)(...)' as it is undefined。我虽然在其定义中包含useState(false),但它具有false 作为默认值?
    • 你把const [isAuthenticated, setAuth] = useContext(AuthContext);更新成const { isAuthenticated, setAuth } = useContext(AuthContext);了吗?
    • 是的,我做到了。我正在将AuthContext 导入该文件。在将其包含在 useContext 中之前,我需要做些什么吗?
    【解决方案2】:

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

    //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
    我认为您的问题可能是您已将默认值放在值对象内的数组中。

    【讨论】:

    • 我喜欢这种方法,但是在将我的默认值更改为对象内部后,我收到错误 TypeError: Cannot destructure property 'isAuthenticated' of 'Object(...)(...)' as it is undefined.
    • @userNick 你能分享代码吗?如果您在某处设置状态,然后在同一渲染中的另一个组件中使用该值,您可能会遇到 useState 是异步的问题,这就是它未定义的原因。
    • 状态正在authContext.js 内的 api 调用中设置。我刚刚更新了原始帖子以包含该代码。
    猜你喜欢
    • 2014-09-20
    • 2018-09-24
    • 1970-01-01
    • 2020-10-21
    • 2011-06-18
    • 1970-01-01
    • 1970-01-01
    • 2020-01-21
    • 1970-01-01
    相关资源
    最近更新 更多