计算使用 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>
);
};
我试图更好地理解 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>
);
};