【问题标题】:Cannot update a component while rendering a different Component - ReactJS渲染不同组件时无法更新组件 - ReactJS
【发布时间】:2021-07-13 10:35:00
【问题描述】:

我知道很多开发人员过去都遇到过类似的问题。我经历了其中的大部分,但无法解决问题。

我正在尝试更新购物车上下文计数器值。以下是代码(store/userCartContext.js 文件)

import React, { createContext, useState } from "react";

const UserCartContext = createContext({
  userCartCTX: [],
  userCartAddCTX: () => {},
  userCartLength: 0
});

export function UserCartContextProvider(props) {
  const [userCartStore, setUserCartStore] = useState([]);

  const addCartProduct = (value) => {
    setUserCartStore((prevState) => {
      return [...prevState, value];
    });
  };

  const userCartCounterUpdate = (id, value) => {
    console.log("hello dolly");
    // setTimeout(() => {
    setUserCartStore((prevState) => {
      return prevState.map((item) => {
        if (item.id === id) {
          return { ...item, productCount: value };
        }
        return item;
      });
    });
    // }, 50);
  };

  const context = {
    userCartCTX: userCartStore,
    userCartAddCTX: addCartProduct,
    userCartLength: userCartStore.length,
    userCartCounterUpdateCTX: userCartCounterUpdate
  };

  return (
    <UserCartContext.Provider value={context}>
      {props.children}
    </UserCartContext.Provider>
  );
}

export default UserCartContext;


这里我已经注释掉了setTimeout 函数。如果我使用 setTimeout,它会完美运行。但我不确定这是否正确。

cartItemEach.js 文件中,我使用以下代码更新上下文

const counterChangeHandler = (value) => {
    let counterVal = value;
    userCartBlockCTX.userCartCounterUpdateCTX(props.details.id, counterVal);
};

CodeSandBox 链接:https://codesandbox.io/s/react-learnable-one-1z5td

当我更新 CART 弹出窗口中的计数器时会出现问题。如果只更新一次计数器,就不会出现任何错误。但是,当您多次更改计数器时,控制台内会弹出此错误。即使出现此错误,它也不会影响整个代码。更新后的计数器值存储在 Context 中的状态中。

【问题讨论】:

  • 您在控制台中看到的错误是什么?
  • @DanielBeck,我已经更新了 CodeSandBox 链接。我得到的警告是——警告:在渲染不同的组件 (Counter) 时无法更新组件 (UserCartContextProvider)。要在 Counter 中找到错误的 setState() 调用,
  • @DanielBeck 我认为问题出在 counter.js 文件(组件 > counter.js)中,我使用props.onCounterChange();将值传递回父组件
  • @DanielBeck 目前我正在修改计数器组件。我使用对象解构 const Counter = ({counterType,currentCounterVal,onCartBtnPush,onCounterChange}) =&gt; {} 而不是道具,而不是在 incrementHandler()decrementHandler() 中调用函数 onCounterChange() 我正在使用这样的 useEffect useEffect(()=&gt;{ onCounterChange(number); },[number, onCounterChange]) 但这也不起作用
  • 请显示userCartCounterUpdateCTX 的调用位置。可能需要用useEffect 或类似名称进行包装。

标签: reactjs react-context


【解决方案1】:

您不能从传递给另一个 setState 函数的函数中调用 setState 函数。在传递给 setState 函数的函数中,您应该只专注于更改该状态。您可以使用useEffect 使该状态更改触发另一个状态更改。

这是重写Counter 类以避免收到警告的一种方法:

  const decrementHandler = () => {
    setNumber((prevState) => {
      if (prevState === 0) {
        return 0;
      }
      return prevState - 1;
    });
  };

  const incrementHandler = () => {
    setNumber((prevState) => {
      return prevState + 1;
    });
  };

  useEffect(() => {
    props.onCounterChange(props.currentCounterVal);
  }, [props.currentCounterVal]);
  // or [props.onCounterChange, props.currentCounterVal] if onCounterChange can change

我不清楚useEffect 是否需要在Counter 类中;鉴于当前值和回调均由父级提供,您可能会将 useEffect 移到父级之外。但这取决于您以及您要完成的工作。

【讨论】:

  • 感谢您帮助我。但它不起作用。现在我收到此警告:index.js:1 警告:已超出最大更新深度。当组件在 useEffect 中调用 setState 时,可能会发生这种情况,但 useEffect 要么没有依赖数组,要么每次渲染时其中一个依赖项发生变化。
  • 我能问你点什么吗?在 userCartContext(store/userCartContext.js 文件)中,我已经注释掉了 setTimeout 函数。如果我使用它,那么它可以完美运行。我可以使用setTimeout 吗?或者如果我使用 setTimeout 会有什么问题?
  • 尝试从useEffect 依赖数组中删除props.onCounterChange,就像上面修改后的代码一样。如果它被定义为内联函数(没有useCallback 包装),它每次都会改变。
猜你喜欢
  • 2020-09-25
  • 2021-07-05
  • 2021-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-06
  • 1970-01-01
相关资源
最近更新 更多