使用useContext useReducer反应登录基本示例

时间:2020-01-30 16:42:25

标签: reactjs typescript react-hooks react-context

我正在使用Typescript。我想

  • 创建上下文
  • 在路由中使用上下文
  • 登录后更新上下文。

我正在关注this tutorial,除了打字稿使我的希望破灭了。见下文

我的App.tsx中有这个

import React from 'react';
import './App.css';

import Login from "./auth/login";
import Home from "./dash/home";
import Header from "./menu";

const initialState = {
  isAuthenticated: false,
  user: null,
  token: null,
};

export const AuthContext = React.createContext(); // <---- This right here complains: 
// Expected 1-2 arguments, but got 0.ts(2554)
// index.d.ts(349, 9): An argument for 'defaultValue' was not provided.

const reducer = (state: any, action: any) => {
  switch (action.type) {
    case "LOGIN":
      return {
        ...state,
        isAuthenticated: true,
        user: action.payload.user,
        token: action.payload.token
      };
    case "LOGOUT":
      localStorage.clear();
      return {
        ...state,
        isAuthenticated: false,
        user: null
      };
    default:
      return state;
  }
};

const App: React.FC = () => {
  const [state, dispatch] = React.useReducer(reducer, initialState);

  return (
    <AuthContext.Provider
      value={{
        state,
        dispatch
      }}
    >
      <Header />
      <div className="App">{!state.isAuthenticated ? <Login /> : <Home />}</div>
    </AuthContext.Provider>
  );
}

export default App;

在我的登录页面上,我有这个:

import React from "react";
import { useForm } from 'react-hook-form';
import axios from 'axios';
import { AuthContext } from "../App";

export const Login = () => {

  const { dispatch } = React.useContext(AuthContext) // <--- This the right way to do it?
  // Where is the "dispatch" magically coming from?

  const onSubmit = (data: any) => {

    axios.post('http://localhost/api/v1/users/login/', data)
      .then(res => {
        console.log(res);
      })
  }

  return (
    <div className="login-container">
      <!-- assume there's a form here -->
    </div>
  );
};
export default Login;

所以

  • 我要为“ defaultValue”输入什么?
  • 登录后如何更新上下文?

编辑:

我想要实现的更多上下文(双关语意)

App.tsx有一个<AuthContext.Provider ...> ... </AuthContext.Provider>,如果我理解正确,则此Context将采用state, dispatch的值,并且根据{!state.isAuthenticated ... }部分,在{{ 1}}和<Login />组件。

根据<Home/>的{​​{1}}设置为<AuthContext.Provider/>

当用户登录登录组件时,我的问题是,我如何通过initialState更新isAuthenticated: false中的值,以便更改路由?< / strong>

2 个答案:

答案 0 :(得分:2)

如果您查看有关React.createContext的文档

仅当树中组件上方没有匹配的Provider时才使用defaultValue参数。这对于隔离测试组件而不包装它们很有帮助。注意:传递undefined作为提供者值不会导致消耗组件使用defaultValue

因此您不需要将任何内容传递给上下文,但是由于打字稿而导致出现错误。

您需要为上下文值创建一个接口。

您将上下文传递为

value={{
    state,
    dispatch
}}

但是创建上下文时需要为此提供一个接口。

export const AuthContext = React.createContext(); // <---- missing interface

这是example的用法。


神奇的“派遣”来自哪里?

useContext的工作方式。

useContext(MyContex)获得的值是MyContext.Provider道具通过value传递的值。

例如

<MyContext.Provider value={fooValue}>
    {/* ... */}
</MyContext.Provider>

// same fooValue from the Provider
const fooValue = useState(MyContext)

编辑

onSubmit内部进行异步调用之后,必须调用dispatch并传递{type: 'LOGIN', payload: DATA_FROM_API},以便在reducer方法中进行操作并将isAuthenticated设置为true

const onSubmit = (data: any) => {
  axios.post('http://localhost/api/v1/users/login/', data)
    .then(res => {        
      console.log(res.data) // <= if this is `payload`, than pass it to dispatch
      dispatch({type: 'LOGIN', payload: res.data})
    })
}

答案 1 :(得分:0)

我遇到了类似的问题,但经过多次试验和错误后,我得以解决。
我正在学习本教程:
链接:https://soshace.com/react-user-login-authentication-using-usecontext-and-usereducer/
代码:https://github.com/nero2009/login-auth-useContext
关于路由的问题也包含在那里。但它是在 JS 中,因此您必须进行一些修改。这是我所做的:

首先,我指定了操作类型,在您的示例中为:

export type AuthenticationAction = { type: 'LOGIN', payload: IPayload } | {type: 'LOGOUT'}

我为我的负载指定了一个接口,但它也可以与“any”一起使用。

然后,我指定了默认值(这可能是您要找的):

const AuthenticationStateContext = React.createContext(initialState)
const AuthenticationDispatchContext = React.createContext({} as Dispatch<AuthenticationAction>)

之后它应该可以工作了。