【问题标题】:Error when creating context + reducer in Typescript在 Typescript 中创建上下文 + reducer 时出错
【发布时间】:2021-09-12 14:53:30
【问题描述】:

这里我想创建一个AuthContext 来将用户状态分享给其他组件。这里我使用 TypeScript 来设置变量类型。但是在尝试解决这个问题时我遇到了很多错误。我对这个问题很困惑。

这是我的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>
    )
}

这是我的减速器:

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,

            }
    }

}

这是我在useReducer 的行中的错误:

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)

这是我在&lt;AuthContext.Provider value={{ state, dispatch }}&gt; 中的错误:

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)

有谁知道解决方案或告诉发生了什么?谢谢

编辑: 当我在登录页面上使用我的上下文时,我遇到了另一个问题。 这是我的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>
    )
}

当我运行代码时,显示如下错误:

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.

我已阅读文档,但我认为我没有违反任何钩子规则。我哪里做错了对不起我是新手。

【问题讨论】:

  • 你的上下文的初始值只是状态,但它需要是一个同时具有状态和调度的对象。
  • 我似乎误解了我应该在上下文中输入的内容,非常感谢您的帮助,它真的帮助了我

标签: reactjs typescript use-context use-reducer


【解决方案1】:

创建的上下文与您使用的上下文不匹配。

创建一个上下文,其value 是一个具有IState 类型的状态对象:

export const AuthContext = createContext<IState>(initialState);

使用一个上下文,其value 是一个具有statedispatch 属性的对象:

<AuthContext.Provider value={{ state, dispatch }}>

为了修复这种不匹配,您必须以与您希望使用它的方式相匹配的方式定义您的AuthContext上下文值必须是具有statedispatch 属性的对象

这里我们为上下文值定义了一个接口。 state 的默认值为initialState,而dispatch 的默认值记录错误消息。

interface AuthContextValue {
    state: IState;
    dispatch: React.Dispatch<IAction>;
}

export const AuthContext = createContext<AuthContextValue>({
    state: initialState,
    dispatch: (action) => console.error("Dispatched action outside of an AuthContext provider", action)
});

TypeScript Playground Link

这是一个更简单的版本,我们在其中内联定义上下文值类型,并且在使用默认值调用 dispatch 时不执行任何操作。

export const AuthContext = createContext<{state: IState; dispatch: React.Dispatch<IAction>}>({
    state: initialState,
    dispatch: () => {},
});

TypeScript Playground Link


我在您的减速器上收到一个不相关的错误,TS 7030“并非所有代码路径都返回值。” reducer 应始终在 switch 中包含 default 大小写,以避免返回 undefined 状态。

default: return state;

【讨论】:

  • 我还有一个问题,当我在登录页面调用createContext 时,出现这样的错误: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 可以再问一次吗?
【解决方案2】:

问题是您将状态和分派作为值传递给提供者,但是当您定义上下文时,您仅将 Istate 作为它的类型传递。您的 Createcontext 应该包括 state 和 dispatch 作为类型。这也会改变初始值。

你提供给提供者的值的类型和你的上下文的类型应该是一样的。

例如:https://www.pluralsight.com/guides/using-react's-context-api-with-typescript

【讨论】:

  • 非常感谢大家的帮助,很有用,解开了我之前的误会
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 2020-05-14
  • 1970-01-01
  • 2018-05-20
  • 2019-06-11
相关资源
最近更新 更多