如何以 useContext 作为依赖项正确使用 useEffect

Mat*_*309 2 reactjs use-effect react-functional-component use-context

我正在开发我的第一个 React 项目,但遇到以下问题。我希望我的代码如何工作:

  • 我将项目添加到可通过上下文访问的数组中(context.items)
  • 我想在组件中运行 useEffect 函数,只要值发生变化,就会显示 context.items

我尝试过的:

  1. 将上下文( 和contextcontext.items列为 useEffect 中的依赖项
  • 这导致组件在值更改时不更新
  1. 列出context.items.length
  • 然而,这导致组件在数组长度发生变化时更新,而不是在单个项目的值发生变化时更新。
  1. 将上下文包装在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;
Run Code Online (Sandbox Code Playgroud)

显示数据的组件(实际上是一个模态):

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]);
Run Code Online (Sandbox Code Playgroud)

对代码的一些评论:

  • 它实际上是在 Type Script 中完成的,涉及一些额外的语法 -content(和设置 Content)是一个状态,它是返回值的一部分,因此可以动态设置某些部分 -exit 是一个关闭模式的函数,也是为什么 props.is包含开放式
  • 使用此.length 扩展,当我从列表中删除一个项目时,模式会显示更改,但是,当我修改它时,不会更改 orderItems 的长度,而只会更改其中一个对象的值。
  • 正如我之前提到的,我找到了一些答案,他们说我应该像这样设置依赖项:...Object.values(<contextVariable>)这在技术上是可行的,但会导致反应抱怨*传递给 useEffect 的最终参数更改了渲染之间的大小。该数组的顺序和大小必须保持不变。*
  • 当我关闭并重新打开模式时,显示的值更改为正确的值,更改props.isOpen表明问题在于上下文依赖性

Emm*_*Joe 5

您可以首先创建应用程序上下文,如下所示,我将使用购物车的示例

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 };
Run Code Online (Sandbox Code Playgroud)

然后,您可以在应用程序中的任何位置使用应用程序上下文,如下所示,每当购物车的长度发生变化时,您都会在购物车中收到通知

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;
Run Code Online (Sandbox Code Playgroud)