Here I want to create an AuthContext
to share user state to other components. Here I am using TypeScript to set the variable type. But I get a lot of errors when trying to solve this problem. And I very confused with this problem.
This my AuthContext
:
import { createContext, ReactNode, useReducer } from 'react'
import { AuthReducer } from './Reducer';
export interface IState {
isAuthenticated: boolean
user: string | null
token: string | null
}
// interface for action reducer
export interface IAction {
type: 'LOGIN' | 'LOGOUT' | 'REGISTER' | 'FORGOT PASSWORD'
payload?: any
}
interface IAuthProvider {
children: ReactNode
}
const initialState = {
isAuthenticated: false,
user: '',
token: ''
}
export const AuthContext = createContext<IState>(initialState);
export const AuthProvider = ({ children }: IAuthProvider) => {
const [state, dispatch] = useReducer(AuthReducer, initialState)
return (
<AuthContext.Provider value={{ state, dispatch }}>
{children}
</AuthContext.Provider>
)
}
And this is my reducer:
import { IAction, IState } from ".";
export const AuthReducer = (state: IState, action: IAction) => {
switch (action.type) {
case 'LOGIN':
localStorage.setItem("user", action.payload.user)
localStorage.setItem("token", action.payload.token)
return {
...state,
isAuthenticated: true,
user: action.payload.user,
token: action.payload.token
}
case 'LOGOUT':
localStorage.clear()
return {
...state,
isAuthenticated: false,
}
}
}
And this is my error in useReducer
's line:
No overload matches this call.
Overload 1 of 5, '(reducer: ReducerWithoutAction<any>, initializerArg: any, initializer?: undefined): [any, DispatchWithoutAction]', gave the following error.
Argument of type '(state: IState, action: IAction) => { isAuthenticated: boolean; user: any; token: any; } | undefined' is not assignable to parameter of type 'ReducerWithoutAction<any>'.
Overload 2 of 5, '(reducer: (state: IState, action: IAction) => { isAuthenticated: boolean; user: any; token: any; } | undefined, initialState: never, initializer?: undefined): [...]', gave the following error.
Argument of type '{ isAuthenticated: boolean; user: string; token: string; }' is not assignable to parameter of type 'never'.ts(2769)
And this is my error in line <AuthContext.Provider value={{ state, dispatch }}>
:
Type '{ state: any; dispatch: React.DispatchWithoutAction; }' is not assignable to type 'IState'.
Object literal may only specify known properties, and 'state' does not exist in type 'IState'.ts(2322)
does anyone know the solution or tell what happened? thank you
Edited:
Here I have another problem when I use my context on Login page.
This is my LoginPage
:
import React, { FC, useContext } from 'react'
import { AuthContext } from '../AuthContext'
export const Login: FC<IProps> = () => {
const { state, dispatch } = useContext(AuthContext)
const login = () => {
dispatch({
type: 'LOGIN',
payload: { ...state, isAuthenticated: !state.isAuthenticated }
})
}
return (
<div>
<input name="username" />
<button onClick={login}></button>
</div>
)
}
and when I running the code, it is show error like this:
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
I've read the documentation, but I don't think I'm breaking any hook rules there. Where did I go wrong sorry I'm new to react.