I was working on a shopping website this morning, using React Typescript and Context API, and want to use React Reducers to manipulate my Shopping Cart State with the custom Types I created for the Product type, including an Items Array and some Functions ... The problem is I don't know how to pass parameters with the Action in the CartReducer function, and would like to know how you would do it
My CartContext
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;
My Types
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
};
Use a discriminated union as your action's type:
// 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 })