我正在使用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;
所以
编辑:
我想要实现的更多上下文(双关语意)
App.tsx
有一个<AuthContext.Provider ...> ... </AuthContext.Provider>
,如果我理解正确,则此Context将采用state, dispatch
的值,并且根据{!state.isAuthenticated ... }
部分,在{{ 1}}和<Login />
组件。
根据<Home/>
的{{1}}设置为<AuthContext.Provider/>
当用户登录登录组件时,我的问题是,我如何通过initialState
更新isAuthenticated: false
中的值,以便更改路由?< / strong>
答案 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>)
之后它应该可以工作了。