计算使用 useContext 添加的次数 - React 和 Typescript

Counting number of times added with useContext - React and Typescript

我试图更好地理解 useContext 挂钩。我正在玩 with this codesandbox,它将左侧组件中的项目添加到右侧。

现在,我想计算它们被添加到列表中的次数(它们分别被点击“添加到购物车”按钮的次数)并将其显示在它们旁边。

我是否需要创建一个全新的上下文和状态挂钩才能访问 resp。物品的价值遍地开花?

我尝试在 addToItemList(item) 函数中实现一个计数器但没有成功。我也试过在它外面实现一个计数器函数,然后实现一个全局的handleClick函数也是徒劳的。

在此先感谢您提供任何提示和提示!

项目列表代码:

import { useContext } from "react";
import { data, Item } from "./data";
import { ItemListContext } from "./ItemList.context";

const items: Item[] = data;
export default function ItemList() {
  const { itemList, setItemList } = useContext(ItemListContext); // get and set list for context

  const addItemToItemList = (item: Item) => {
    //you are using the itemList to see if item is already in the itemList
    if (!itemList.includes(item)) setItemList((prev) => [...prev, item]);
  };
  return (
    <div className="itemlist">
      {items.map((item, index) => (
        <div style={{ marginBottom: 15 }} key={index}>
          <div style={{ fontWeight: 800 }}>{item.name}</div>
          <div>{item.description}</div>
          <button onClick={() => addItemToItemList(item)}>
            Add to sidebar
          </button>
        </div>
      ))}
    </div>
  );
}


以及包含添加项目的容器的代码:

import { useContext } from "react";
import { ItemListContext } from "./ItemList.context";
import { Link, useHistory } from "react-router-dom";
export default function ItemContainer() {
  const history = useHistory(); //useHistory hooks doc: https://reactrouter.com/web/api/Hooks
  const { itemList } = useContext(ItemListContext);
  const onNavigate = () => {
    history.push("/selectedItemList");
  };
  return (
    <div style={{ flexGrow: 4 }}>
      <h1 style={{ textAlign: "center" }}>List of items</h1>

      <p>Number of items: {itemList.length}</p>
      {itemList.length > 0 && (
        <ul>
          {itemList.map((item, i) => (
            <li key={i}>{item.name}</li>
          ))}
        </ul>
      )}
      <div>
        <button>
          {" "}
          <Link to="/selectedItemList"> selected list details</Link>
        </button>
        <div>
          <button type="button" onClick={onNavigate}>
            selected list with useHistory hook
          </button>
        </div>
      </div>
    </div>
  );
}


ItemList.context.tsx

import React, {
  createContext,
  Dispatch,
  FunctionComponent,
  useState
} from "react";
import { Item } from "./data";
type ItemListContextType = {
  itemList: Item[]; // type of your items thata I declare in data.ts
  setItemList: Dispatch<React.SetStateAction<Item[]>>; //React setState type
};
export const ItemListContext = createContext<ItemListContextType>(
  {} as ItemListContextType
);

export const ItemListContextProvider: FunctionComponent = ({ children }) => {
  const [itemList, setItemList] = useState<Item[]>([]);

  return (
    <ItemListContext.Provider
      value={{ itemList: itemList, setItemList: setItemList }}
    >
      {children}
    </ItemListContext.Provider>
  );
};

将包装器方法添加到上下文。

这假设名称是唯一的。

type ItemListContextType = {
  itemList: Item[]; // type of your items thata I declare in data.ts
  addItem: (item: Item) => void;
  removeItem: (item: Item) => void;
  counter: { [itemName: string]: number };
};
export const ItemListContext = createContext<ItemListContextType>(
  {} as ItemListContextType
);

export const ItemListContextProvider: FunctionComponent = ({ children }) => {
  const [itemList, setItemList] = useState<Item[]>([]);
  const [counter, setCounter] = useState<{ [itemName: string]: number }>({});

  const addItem = useCallback((item) => {
    setCounter((prev) => ({
      ...prev,
      [item.name]: (prev[item.name] || 0) + 1,
    }));
    setItemList((prev) => [...prev, item]);
  }, []);
  const removeItem = useCallback((itemName) =>
    setItemList((prev) => prev.filter((it) => it.name !== itemName)), []
  );

  return (
    <ItemListContext.Provider
      value={{ itemList: itemList, addItem, removeItem, counter }}
    >
      {children}
    </ItemListContext.Provider>
  );
};