如何将 useContext 作为依赖项正确使用 useEffect
How to use useEffect correctly with useContext as a dependency
我正在处理我的第一个 React 项目,我遇到了以下问题。
我希望我的代码如何工作:
- 我将项目添加到上下文可访问的数组中 (context.items)
- 我想 运行 组件中的 useEffect 函数,只要值发生变化,就会显示 context.items
我尝试了什么:
- 将上下文(
context
和 context.items
)列为 useEffect 中的依赖项
- 这导致组件在值更改时未更新
- 列出
context.items.length
- 然而,当数组的长度发生变化时,这会导致组件更新,而不是当单个项目的值发生变化时。
- 在
Object.values(context)
中包装上下文
- 结果正是我想要的,除了 React 现在抱怨 *传递给 useEffect 的最后一个参数改变了渲染之间的大小。该数组的顺序和大小必须保持不变。 *
您是否知道解决此 React 警告的任何方法或运行在上下文值更改时使用 useEffect 的不同方法?
嗯,不想添加代码,希望这是我这边的一些简单错误,但即使有了一些答案,我仍然无法解决这个问题,所以在这里,减少希望简化.
上下文组件:
const NewOrder = createContext({
orderItems: [{
itemId: "",
name: "",
amount: 0,
more:[""]
}],
addOrderItem: (newOItem: OrderItem) => {},
removeOrderItem: (oItemId: string) => {},
removeAllOrderItems: () => {},
});
export const NewOrderProvider: React.FC = (props) => {
// state
const [orderList, setOrderList] = useState<OrderItem[]>([]);
const context = {
orderItems: orderList,
addOrderItem: addOItemHandler,
removeOrderItem: removeOItemHandler,
removeAllOrderItems: removeAllOItemsHandler,
};
// handlers
function addOItemHandler(newOItem: OrderItem) {
setOrderList((prevOrderList: OrderItem[]) => {
prevOrderList.unshift(newOItem);
return prevOrderList;
});
}
function removeOItemHandler(oItemId: string) {
setOrderList((prevOrderList: OrderItem[]) => {
const itemToDeleteIndex = prevOrderList.findIndex((item: OrderItem) => item.itemId === oItemId);
console.log(itemToDeleteIndex);
prevOrderList.splice(itemToDeleteIndex, 1);
return prevOrderList;
});
}
function removeAllOItemsHandler() {
setOrderList([]);
}
return <NewOrder.Provider value={context}>{props.children}</NewOrder.Provider>;
};
export default NewOrder;
显示数据的组件(实际上是模态):
const OrderMenu: React.FC<{ isOpen: boolean; hideModal: Function }> = (
props
) => {
const NewOrderContext = useContext(NewOrder);
useEffect(() => {
if (NewOrderContext.orderItems.length > 0) {
const oItems: JSX.Element[] = [];
NewOrderContext.orderItems.forEach((item) => {
const fullItem = {
itemId:item.itemId,
name: item.name,
amount: item.amount,
more: item.more,
};
oItems.push(
<OItem item={fullItem} editItem={() => editItem(item.itemId)} key={item.itemId} />
);
});
setContent(<div>{oItems}</div>);
} else {
exit();
}
}, [NewOrderContext.orderItems.length, props.isOpen]);
对代码的一些评论:
- 它实际上是在 Type Script 中完成的,涉及一些额外的语法
-内容(和设置内容)是一个状态,然后是 return 值的一部分,因此可以动态设置某些部分
-exit 是一个关闭模态的函数,也是为什么 props.is Open 包含在内
- 有了这个
.length
扩展,当我从列表中删除一个项目时,模态显示会改变,但是,当我修改它时不会改变 orderItems 的长度,但只会改变其中一个对象的值
- 正如我之前提到的,我找到了一些答案,他们说我应该像这样设置依赖关系:
...Object.values(<contextVariable>)
这在技术上是可行的,但导致反应抱怨 *传递给 useEffect 的最后一个参数改变了大小渲染。该数组的顺序和大小必须保持不变。 *
- 当我关闭并重新打开模式时,显示的值更改为正确的值,更改
props.isOpen
表明问题出在上下文相关性上
您可以尝试将上下文变量传递给 useEffect 依赖数组,并在 useEffect 主体内部执行检查以查看值是否不为空。
您可以按如下方式创建您的应用上下文,我将使用购物车作为示例
import * as React from "react"
const AppContext = React.createContext({
cart:[]
});
const AppContextProvider = (props) => {
const [cart,setCart] = React.useState([])
const addCartItem = (newItem)=>{
let updatedCart = [...cart];
updatedCart.push(newItem)
setCart(updatedCart)
}
return <AppContext.Provider value={{
cart
}}>{props.children}</AppContext.Provider>;
};
const useAppContext = () => React.useContext(AppContext);
export { AppContextProvider, useAppContext };
然后您可以在应用中的任何位置使用应用上下文,如下所示,只要购物车的长度发生变化,您就会在购物车中收到通知
import * as React from "react";
import { useAppContext } from "../../context/app,context";
const ShoppingCart: React.FC = () => {
const appContext = useAppContext();
React.useEffect(() => {
console.log(appContext.cart.length);
}, [appContext.cart]);
return <div>{appContext.cart.length}</div>;
};
export default ShoppingCart;
我正在处理我的第一个 React 项目,我遇到了以下问题。 我希望我的代码如何工作:
- 我将项目添加到上下文可访问的数组中 (context.items)
- 我想 运行 组件中的 useEffect 函数,只要值发生变化,就会显示 context.items
我尝试了什么:
- 将上下文(
context
和context.items
)列为 useEffect 中的依赖项
- 这导致组件在值更改时未更新
- 列出
context.items.length
- 然而,当数组的长度发生变化时,这会导致组件更新,而不是当单个项目的值发生变化时。
- 在
Object.values(context)
中包装上下文
- 结果正是我想要的,除了 React 现在抱怨 *传递给 useEffect 的最后一个参数改变了渲染之间的大小。该数组的顺序和大小必须保持不变。 *
您是否知道解决此 React 警告的任何方法或运行在上下文值更改时使用 useEffect 的不同方法?
嗯,不想添加代码,希望这是我这边的一些简单错误,但即使有了一些答案,我仍然无法解决这个问题,所以在这里,减少希望简化.
上下文组件:
const NewOrder = createContext({
orderItems: [{
itemId: "",
name: "",
amount: 0,
more:[""]
}],
addOrderItem: (newOItem: OrderItem) => {},
removeOrderItem: (oItemId: string) => {},
removeAllOrderItems: () => {},
});
export const NewOrderProvider: React.FC = (props) => {
// state
const [orderList, setOrderList] = useState<OrderItem[]>([]);
const context = {
orderItems: orderList,
addOrderItem: addOItemHandler,
removeOrderItem: removeOItemHandler,
removeAllOrderItems: removeAllOItemsHandler,
};
// handlers
function addOItemHandler(newOItem: OrderItem) {
setOrderList((prevOrderList: OrderItem[]) => {
prevOrderList.unshift(newOItem);
return prevOrderList;
});
}
function removeOItemHandler(oItemId: string) {
setOrderList((prevOrderList: OrderItem[]) => {
const itemToDeleteIndex = prevOrderList.findIndex((item: OrderItem) => item.itemId === oItemId);
console.log(itemToDeleteIndex);
prevOrderList.splice(itemToDeleteIndex, 1);
return prevOrderList;
});
}
function removeAllOItemsHandler() {
setOrderList([]);
}
return <NewOrder.Provider value={context}>{props.children}</NewOrder.Provider>;
};
export default NewOrder;
显示数据的组件(实际上是模态):
const OrderMenu: React.FC<{ isOpen: boolean; hideModal: Function }> = (
props
) => {
const NewOrderContext = useContext(NewOrder);
useEffect(() => {
if (NewOrderContext.orderItems.length > 0) {
const oItems: JSX.Element[] = [];
NewOrderContext.orderItems.forEach((item) => {
const fullItem = {
itemId:item.itemId,
name: item.name,
amount: item.amount,
more: item.more,
};
oItems.push(
<OItem item={fullItem} editItem={() => editItem(item.itemId)} key={item.itemId} />
);
});
setContent(<div>{oItems}</div>);
} else {
exit();
}
}, [NewOrderContext.orderItems.length, props.isOpen]);
对代码的一些评论:
- 它实际上是在 Type Script 中完成的,涉及一些额外的语法 -内容(和设置内容)是一个状态,然后是 return 值的一部分,因此可以动态设置某些部分 -exit 是一个关闭模态的函数,也是为什么 props.is Open 包含在内
- 有了这个
.length
扩展,当我从列表中删除一个项目时,模态显示会改变,但是,当我修改它时不会改变 orderItems 的长度,但只会改变其中一个对象的值 - 正如我之前提到的,我找到了一些答案,他们说我应该像这样设置依赖关系:
...Object.values(<contextVariable>)
这在技术上是可行的,但导致反应抱怨 *传递给 useEffect 的最后一个参数改变了大小渲染。该数组的顺序和大小必须保持不变。 * - 当我关闭并重新打开模式时,显示的值更改为正确的值,更改
props.isOpen
表明问题出在上下文相关性上
您可以尝试将上下文变量传递给 useEffect 依赖数组,并在 useEffect 主体内部执行检查以查看值是否不为空。
您可以按如下方式创建您的应用上下文,我将使用购物车作为示例
import * as React from "react"
const AppContext = React.createContext({
cart:[]
});
const AppContextProvider = (props) => {
const [cart,setCart] = React.useState([])
const addCartItem = (newItem)=>{
let updatedCart = [...cart];
updatedCart.push(newItem)
setCart(updatedCart)
}
return <AppContext.Provider value={{
cart
}}>{props.children}</AppContext.Provider>;
};
const useAppContext = () => React.useContext(AppContext);
export { AppContextProvider, useAppContext };
然后您可以在应用中的任何位置使用应用上下文,如下所示,只要购物车的长度发生变化,您就会在购物车中收到通知
import * as React from "react";
import { useAppContext } from "../../context/app,context";
const ShoppingCart: React.FC = () => {
const appContext = useAppContext();
React.useEffect(() => {
console.log(appContext.cart.length);
}, [appContext.cart]);
return <div>{appContext.cart.length}</div>;
};
export default ShoppingCart;