如何使我的action.payload成为目标,并根据我使用Redux在页面上单击的按钮显示特定的项目?

enxuqcxy  于 2022-11-12  发布在  其他
关注(0)|答案(1)|浏览(172)

好的,我现在正在用Redux和Typescript写一个React应用程序,但是我很难找到一个问题的解决方案,因为我对Redux还很陌生。这是一个餐馆在线订单页面,我在Order.tsx页面中有两个组件(MenuItems.tsx和Cart.tsx),还有一个Rootreducer.tsx,它包含了我所有的菜单信息、我的根还原器和商店:

页面上垂直黑线的左边是MenuItems.tsx组件中的所有内容,右边是Cart.tsx组件。当我单击Add To Cart时,食物被推送到我所在州的items[]数组中,并显示在购物车中。
问题是,当我在一个部分中的任何项目上单击“添加到购物车”时,它返回该部分中的每个食品项目,或者action.payload包含的整个数组(目前它将有效负载中的所有5个食品名称及其价格发送到Cart组件中)。虽然它是工作代码,但我特别希望它能够在我单击某个特定食品上的按钮时,我只想让购物车显示那一个项目,而不是所有5餐在Starters部分。
正在访问的我的初始菜单数据:

const initialMenu = [
  {
    section: "Starters",
    list: [
      {
        img: chickenwings,
        name: "Chicken Pub Wings",
        desc: "Served with blue cheese dip and celery sticks. Choose your style plain and crispy, mild sticky barbecue or hot spicy Louisiana sauce",
        price: "$9 for 6 wing basket, $14 for 12 wing basket",
      },
      {
        img: soupoftheday,
        name: "Soup of the Day",
        desc: "Served with Dublin Soda Bread",
        price: "$6",
      },
      {
        img: potatoskins,
        name: "Galway Potato Skins",
        desc: "Served with Irish bacon, cheddar and chives",
        price: "$9",
      },
      {
        img: friedpickles,
        name: "Fried Pickles",
        desc: "Thick-cut chips, beer battered, with house-made ranch",
        price: "$8",
      },
      {
        img: mozzarellasticks,
        name: "Mozzarella Sticks",
        desc: "Slightly breaded, golden fried and served with warm marinara sauce",
        price: "$8",
      },
    ],
  },
  {
    section: "Soups & Salads",
    list: [
      {
        img: caesarsalad,
        name: "Caesar Salad",
        desc: "Crisp romaine, parmesan cheese, brioche croutons, classic dressing",
        price: "$14",
      },
      {
        img: cobbsalad,
        name: "Cobb Salad",
        desc: "Romaine, tomato, egg, red onion, avocado, blue cheese, smoked bacon",
        price: "$15",
      },
      {
        img: housesalad,
        name: "House Salad",
        desc: "Mixed greens, tomato, cucumber, croutons, shredded cheese. Can add grilled or fried chicken for $3",
        price: "$10",
      },
      {
        img: greeksalad,
        name: "Greek Chicken Salad",
        desc: "Romaine, black olives, banana peppers, tomato, cucumber, feta, and greek feta dressing",
        price: "$11",
      },
      {
        img: potatosoup,
        name: "Loaded Potato Soup",
        desc: "Topped with cheese and crispy bacon and served with dipping bread",
        price: "$7",
      },
      {
        img: beefstew,
        name: "Guinness Beef Stew",
        desc: "Braised beef, root vegetables and potatoes simmered in a Guinness broth",
        price: "$14",
      },
    ],
  },
  ...

MenuItems.tsx的代码:

import { useAppSelector, useAppDispatch } from "../app/hooks";
import "../styles/Order.scss";
import "../App.tsx";

const MenuItems = (props: any): JSX.Element => {
  const dispatch = useAppDispatch();
  // console.log(props);
  const menu = useAppSelector((state) => state.menu);
  return (
    <div>
      <div className="menu-nav">
        <ul>
          <li>
            <a href="#Starters">Starters</a>
          </li>
          <li>
            <a href="#Soups & Salads">Soups & Salads</a>
          </li>
          <li>
            <a href="#Traditional Classics">Traditional Classics</a>
          </li>
          <li>
            <a href="#Burgers & Sandwiches">Burgers & Sandwiches</a>
          </li>
          <li>
            <a href="#Sides">Sides</a>
          </li>
          <li>
            <a href="#Drinks">Drinks</a>
          </li>
          <li>
            <a href="#Desserts">Desserts</a>
          </li>
        </ul>
      </div>
      <div className="item-flex">
        {menu.map((item, index) => {
          return (
            <div key={index} className="">
              <h1 id={item.section}>{item.section}</h1>
              <div className="item-grid">
                {item.list.map((c, i) => {
                  return (
                    <div key={i} className="item-section">
                      <img src={c.img} alt="food image" />
                      <p>{c.name}</p>
                      <p>{c.desc}</p>
                      <p>{c.price}</p>
                      <button
                        key={c.name}
                        onClick={() =>
                          dispatch({
                            type: "ADD_TO_CART",
                            payload: item,
                          })
                        }
                      >
                        Add To Cart
                      </button>
                    </div>
                  );
                })}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
};

export default MenuItems;

购物车代码.tsx:

import { NavLink } from "react-router-dom";
import { useAppDispatch, useAppSelector } from "../app/hooks";
import "../styles/Order.scss";

const Cart = (): JSX.Element => {
  const cart = useAppSelector((state) => state.items);
  const dispatch = useAppDispatch();
  return (
    <div className="">
      <h1>Cart</h1>
      {cart.map((item, index) => {
        return (
          <div key={index}>
            {item.list.map((c, i) => {
              return (
                <div key={i}>
                  <p>{c.name}</p>
                  <p>{c.price}</p>
                  <button
                    key={c.name}
                    onClick={() =>
                      dispatch({ type: "REMOVE_FROM_CART", payload: item })
                    }
                  >
                    Remove From Cart
                  </button>
                </div>
              );
            })}
          </div>
        );
      })}
      <NavLink to="/ordercomplete">Order Complete</NavLink>
    </div>
  );
};

export default Cart;

rootReducer.tsx:

type Action = {
  type: string;
  payload?: any;
};

interface CommonFood {
  img: any;
  name: string;
  desc: string;
  price: string;
}

interface FoodDetail {
  section: string;
  list: Array<CommonFood>;
}

const initialMenu = [
  ...
 };

type State = {
  menu: FoodDetail[];
  items: FoodDetail[];
};

const initialState: State = {
  menu: initialMenu,
  items: [],
};

const rootReducer = (state = initialState, action: Action) => {
  switch (action.type) {
    case "ADD_TO_CART":
      const newItems = state.items;
      console.log(newItems);
      return { ...state, items: [...newItems, action?.payload] };
    case "REMOVE_FROM_CART":
      return {
        ...state,
        items: [...state.items].filter((item) => item !== action.payload),
      };
    default:
      return state;
  }
};

export default rootReducer;

那么,基于我给出的代码,我如何改变根化简器中的“ADD_TO_CART”操作类型,使其不再给出数组中的所有5个项,而是指向数组中的一个项呢?或者我需要改变其他的东西吗?我知道我需要以某种方式指向它的索引来获取特定的值,但是我一直在为该尝试什么而挣扎。任何帮助都非常感谢!

1cklez4t

1cklez4t1#

您的分派会指涉功能表状态中的料号。每个料号实际上都是描述功能表区段的对象,而不是实际的购物车料号。
我知道我需要以某种方式将它的索引作为目标来获取那个特定的值,但我一直在为该尝试什么而挣扎。
正如您所描述的问题,您不需要索引,因为您只是将项目推入购物车。您只需要传递当前的食品项目c,如下所示:

dispatch({ type: "ADD_TO_CART", payload: c })

但是,如果您多次将相同的项目添加到购物车中,则可能希望增加该项目的计数,而不是将重复的项目推送到购物车中。
为此,您将需要某种类型的id来了解要递增的项,以及quantity来跟踪每个项的计数。

溶液

首先,您的state.items应该是CommonFood[]类型,而不是FoodDetail[]类型,这样您的购物车就代表了单个商品。
然后,CommonFood或您决定用作购物车项目的任何项目都需要同时具有idquantity属性:

{
  name: "Fried Pickles",
  id: 0,
  quantity: 0,
  img: friedpickles,
  desc: "Thick-cut chips, beer battered, with house-made ranch",
  price: "$8",
}

您还希望能够访问MenuItems.tsx中的当前购物车状态,以便将其传递给您的操作。
因此,在MenuItems.tsx中,您将拥有:

dispatch({ type: "ADD_TO_CART", payload: {cartItems, itemToAdd} })

在这里,我已经用cartItems替换了当前代码中的state.items,用itemToAdd替换了当前代码中的c,这使得后面的代码更容易阅读。
然后,在你的行动中:

case "ADD_TO_CART":
  const { cartItems, itemToAdd } = action.payload;

  const newCartItems = (cartItems, itemToAdd) => {
    const existingCartItem = cartItems.find(
      (cartItem) => cartItem.id === itemToAdd.id
    );

    if (existingCartItem) {
      return cartItems.map((cartItem) =>
        cartItem.id === itemToAdd.id
          ? { ...cartItem, quantity: cartItem.quantity + 1 }
          : cartItem
      );
    }

    return [...cartItems, { ...itemToAdd, quantity: 1 }];
  };

  return { ...state, items: newCartItems };

在此操作中,我们将检查购物车中是否存在该项目。
如果是,我们会增加该项目的数量。
如果没有,我们将添加该项目,并将数量设置为1。

相关问题