Ошибка ввода с использованием useReducer и Context с Typescript - PullRequest
0 голосов
/ 09 апреля 2020

Я пытаюсь включить Auth с useReducer и Context в приложение React, но у меня есть ошибка типа в

<UserDispatchContext.Provider value={dispatch}>

Ошибка:

Type 'Dispatch<Action>' is not assignable to type '(state: User, action: Action) =>
{ id: number | null; username: string | null; email: string | null; role: 'user' | 'admin'; }'.
  Types of parameters 'value' and 'state' are incompatible.
    Property 'type' is missing in type 'User' but required in type 'Action'.

Это мои типы

export interface Action { type: 'login' | 'logout' }

export interface User {
    id: number | null
    username: string | null
    email: string | null
    role: 'user' | 'admin'
}

это Auth.tsx

import React, { useReducer, useContext } from 'react'
import { NextPage } from 'next'
import { User, Action } from '../@types/auth'

const user: User = {
    id: null,
    username: null,
    email: null,
    role: null
}

const reducer = (state: User, action: Action) => {
    switch (action.type) {
        case 'login':
            return {...state}
        default:
          return {...state, ...user}
    }
}

const UserStateContext = React.createContext<User>(user)
const UserDispatchContext = React.createContext<typeof reducer>(reducer)

export const AuthProvider: NextPage = ({ children }) => {

    const [ state, dispatch ] = useReducer(reducer, user)

    return (
        <UserStateContext.Provider value={state}>
            <UserDispatchContext.Provider value={dispatch}>
                {children}
            </UserDispatchContext.Provider>
        </UserStateContext.Provider>
    )
}

export const useAuth = () => useContext(UserStateContext)
export const useDispatchAuth = () => useContext(UserDispatchContext)

Я что-то пробовал, но не могу понять. Может быть, я не совсем понял, как работает useReducer.

Заранее спасибо

1 Ответ

2 голосов
/ 09 апреля 2020

Мне сложно отладить этот код, просто взглянув на него, но я собираюсь показать вам очень похожий код, который у меня есть, в надежде, что вы сможете что-то из него извлечь. Главное, что я использовал typesafe-действия: https://github.com/piotrwitek/typesafe-actions

index.tsx:

import React, { createContext, useContext, useEffect, useReducer } from 'react';
import { ActionType } from 'typesafe-actions';

import * as actions from './app.actions';
import * as userActions from './user/actions';

import * as fromUser from './user/reducer';


interface State {
  user: fromUser.State,
}

const appReducer = (state: State, action: ActionType<typeof actions>) => ({
  user: fromUser.reducer(state.user, action as ActionType<typeof userActions>),
});

const initialState: State = {
  user: fromUser.initialState,
};


const StateContext = createContext(initialState);
const DispatchContext = createContext((_: ActionType<typeof actions>) => { });

interface ProviderProps { children: React.ReactNode }

export const StoreProvider: React.FC<ProviderProps> = ({ children }) => {
  const [state, dispatch] = useReducer(appReducer, initialState);

  useEffect(() => {
    dispatch(actions.appStart());
    return () => dispatch(actions.appEnd());
  }, []);

  return (
    <StateContext.Provider value={state}>
      <DispatchContext.Provider value={dispatch}>
        {children}
      </DispatchContext.Provider>
    </StateContext.Provider>
  );
};

export function useStore() {
  return useContext(StateContext);
}

export function useDispatch() {
  return useContext(DispatchContext);
}

. / User / actions:

export const ADD_USER = 'user/ADD_USER';
export const addUser = (user: string) => ({
  type: ADD_USER,
  user,
} as const);

export const REMOVE_USER = 'user/REMOVE_USER';
export const removeUser = () => ({
  type: REMOVE_USER,
} as const);

. / Пользователь / редуктор:

import { ActionType } from 'typesafe-actions';

import * as actions from './actions';


export interface State {
  userName: string | null,
}

export const initialState: State = {
  userName: null,
};

export const reducer = (state = initialState, action: ActionType<typeof actions>): State => {
  switch (action.type) {
    case actions.ADD_USER: {
      return {
        userName: action.user,
      };
    }
    case actions.REMOVE_USER: {
      return {
        userName: null,
      };
    }
    default: return state;
  }
};
...