Как создать сокращения для пользовательского типа

#reactjs #typescript #react-context

Вопрос:

Сегодня утром я работал над торговым сайтом, используя API React Typescript и контекст, и хочу использовать редукторы React для управления состоянием моей корзины покупок с помощью пользовательских типов, которые я создал для типа продукта, включая массив товаров и некоторые функции … Проблема в том, что я не знаю, как передавать параметры с помощью действия в функции CartReducer, и хотел бы знать, как бы вы это сделали

Мой картотекст

 import * as React from 'react';
import { useQuery } from "react-query";





type ICartContext = [IProductItem[] | undefined, React.Dispatch<React.SetStateAction<IProductItem[] | undefined>>];

export const CartContext = React.createContext<ICartContext>([[], () => null]);



type Action = "Add" | "Update" | "Remove"

const CartReducer = (state: IProductItem[], action: Action) => {

    return state
}


const CartProvider: React.FC<{}> = ({children}: { children?: React.ReactNode }) => {

    const [cart, setCart] = React.useReducer(CartReducer, [], undefined)


    return (
        <CartContext.Provider value={[cart, setCart]}>
            {children}
        </CartContext.Provider>
    );

};

export default CartProvider;
 

Мои Типы

 interface IProductItem{
    id: number
    title: string
    description: string
    category: string
    image: string
    price: number
    quantity: number
}

type ProductType = {
    items: IProductItem[];
    saveItem: (item: IProductItem) => void
    updateItem: (id: number) => void
    removeItem: (id: number) => void
};
 

Ответ №1:

Используйте дискриминируемый союз в качестве типа вашего действия:

 // each specific action includes a `type` property

interface AddAction {
  type: "Add";
  addedProduct: IProductItem;
}
interface UpdateAction {
  type: "Update";
  updatedProduct: IProductItem;
}
interface RemoveAction {
  type: "Remove";
  removedProduct: IProductItem;
}

// Action is a union of all the possible actions
type Action = AddAction | UpdateAction | RemoveAction;

const CartReducer = (state: IProductItem[], action: Action) => {
  // Since `type` is the only property all actions have in common,
  // it's the only property that can be accessed until narrowing
  // it with a condition or a switch statement

  switch (action.type) {
    case "Add":
      // can access action.addedProduct here
      return state;

    case "Update":
      // can access action.updatedProduct here
      return state;

    case "Remove":
      // can access action.removedProduct here
      return state;
  }
};

// elsewhere:
dispatch({ type: "Add", addedProduct: product })
 

Комментарии:

1. Привет @Стивен Дженнингс, спасибо за ваш ответ, я сделал то, что вы мне сказали, но когда я пытаюсь экспортировать setState значения поставщика, я получаю следующую ошибку… как я могу это исправить : Type 'Dispatch<Action>' is not assignable to type 'Dispatch<SetStateAction<IProductItem[] | undefined>>'. Type 'SetStateAction<IProductItem[] | undefined>' is not assignable to type 'Action'. Type 'undefined' is not assignable to type 'Action'.ts(2322)

2. Я думаю , что это исходит из типа ICartContext , его, вероятно, нужно обновить, чтобы принять Dispatch<Action> вместо Dispatch<SetStateAction<IProductItem[] | undefined>>

3. Да, я исправил это вчера, теперь все работает хорошо, спасибо за вашу помощь.. Ценю это