【问题标题】:Counting number of times added with useContext - React and Typescript使用 useContext 计算添加的次数 - React 和 Typescript
【发布时间】:2021-07-05 14:18:23
【问题描述】:

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

现在,我想计算他们被添加到列表中的次数(他们相应的添加到购物车按钮被点击了多少次)并将其显示在他们旁边。

我是否需要创建一个全新的上下文和状态挂钩才能访问相应的?项目的价值?

我尝试在 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>
  );
};

【问题讨论】:

  • 我看不到您的上下文是在哪里定义的,以及上下文提供程序在哪里使用。请将它们添加到代码中。
  • 您好,感谢您的回答。我在消息中添加了上下文提供程序。

标签: reactjs typescript react-router react-hooks use-context


【解决方案1】:

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

这假定名称是唯一的。

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>
  );
};

【讨论】:

  • 再次您好,非常感谢您的详细回答。我实现了您的代码并重构了其他组件,所以现在我设法使您的 addItem 和 removeItem 的新实现工作。我现在唯一难以访问的是柜台本身。要使用您的新 addItem,我只需要做 if (!itemList.includes(item)) addItem(item) ,那么柜台呢?再次感谢你。感谢您的回答,我学到了很多关于 useContext 的知识!
猜你喜欢
  • 2021-07-04
  • 2020-09-29
  • 1970-01-01
  • 1970-01-01
  • 2021-09-11
  • 2020-01-16
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多