【问题标题】:Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array超过最大更新深度。当组件在 useEffect 中调用 setState 时会发生这种情况,但 useEffect 要么没有依赖数组
【发布时间】:2021-05-13 11:28:30
【问题描述】:

我正在尝试将 基于类的 组件转换为 功能性 组件。如果我在 useEffect 挂钩中使用 componentDidMount 下的相同代码,则会收到上述错误。

// Class based component

    class Container extends Component {
      state = {
        elements: [],
        counter: 1,
        bgColor: "#ffffff",
        botTextColor: "#000000",
        botBGColor: "#aaaaaa",
        userTextColor: "#000000",
        userBgColor: "#aaaaaa",
      };
      
      componentDidMount = async () => {
        this.setState({
          bgColor: this.props.chat.currentChat.bgColor,
          botTextColor: this.props.chat.currentChat.botTextColor,
          botBGColor: this.props.chat.currentChat.botBGColor,
          userTextColor: this.props.chat.currentChat.userTextColor,
          userBgColor: this.props.chat.currentChat.userBgColor,
        });
        
        
        this.setState({
          elements:
            this.props.chat.currentChat.elements &&
            this.props.chat.currentChat.elements.length > 0
              ? elements
              : [
                  {
                    id: "0",
                    data: {
                      label: (
                        <WelcomeNode
                          id={"0"}
                          images={this.props.chat.media.map((e) => e.file)}
                          updateChoices={(choices) =>
                            this.updateChoices("0", choices)
                          }
                          updateMessage={(message) =>
                            this.updateMessage("0", message)
                          }
                          updateImage={(e) => this.updateImage(e, "0")}
                          addEdge={this.addEdgeCustom}
                          deleteEdgeChoice={(index) =>
                            this.deleteEdgeChoice("0", index)
                          }
                          isChoiceConnected={(index) =>
                            this.isChoiceConnected("0", index)
                          }
                        ></WelcomeNode>
                      ),
                      message: "",
                      choices: [],
                      type: "welcome",
                      id: "0",
                    },
                    className: "node-elements",
                    position: { x: 100, y: 100 },
                  },
                ],
          counter: elements.length > 0 ? elements.length : 1,
        });
        
       }
      
     }

以下是发生错误的功能组件

// Functional component

const initialState = {.....}

const Container = () => {
  const [state, setState] = useState(initialState);
  const { auth, chat } = useSelector((state) => ({ ...state }));
  const dispatch = useDispatch();
  const history = useHistory();

  useEffect(() => {
    setState({
      ...state,
      bgColor: chat.currentChat.bgColor,
      botTextColor: chat.currentChat.botTextColor,
      botBGColor: chat.currentChat.botBGColor,
      userTextColor: chat.currentChat.userTextColor,
      userBgColor: chat.currentChat.userBgColor,
    });

    setState({
        ...state,
        elements:
          chat.currentChat.elements && chat.currentChat.elements.length > 0
            ? elements
            : [
                {
                  id: "0",
                  data: {
                    label: (
                      <WelcomeNode
                        id={"0"}
                        images={chat.media.map((e) => e.file)}
                        updateChoices={(choices) => updateChoices("0", choices)}
                        updateMessage={(message) => updateMessage("0", message)}
                        updateImage={(e) => updateImage(e, "0")}
                        addEdge={(e) => addEdgeCustom(e)}
                        deleteEdgeChoice={(index) =>
                          deleteEdgeChoice("0", index)
                        }
                        isChoiceConnected={(index) =>
                          isChoiceConnected("0", index)
                        }
                      ></WelcomeNode>
                    ),
                    message: "",
                    choices: [],
                    type: "welcome",
                    id: "0",
                  },
                  className: "node-elements",
                  position: { x: 100, y: 100 },
                },
              ],
        counter: elements.length > 0 ? elements.length : 1,
      });

   
  }, []);

}
  

引发以下错误并且浏览器崩溃未捕获(在承诺中)错误:重新渲染过多。 React 限制渲染次数以防止无限循环。

【问题讨论】:

  • useEffect 在组件呈现时触发。 setState 触发重新渲染,通过在 useEffect 中调用 setState,您正在创建一个无限循环。
  • 感谢回复,请问哪里可以设置状态呢?
  • tbh,我不明白为什么您的状态会跟踪其中的任何元素。看起来这些值都可以通过 useSelector 获得,而您只是将它们复制到状态中。您展示的唯一内容是,如果聊天为空,您正在设置欢迎消息,但这可以在常规渲染过程中(或更多)轻松完成。
  • 我刚刚阅读了 useSelector,现在我对你在做什么感到更加困惑。看起来您正在从您的状态创建一个 react redux 选择器,然后您正在尝试从选择器设置状态。这是正确的吗?
  • 我正在跟踪另外 10 个状态,因为它会变得太长,所以我没有在此处包括在内,我正在使用 useSelector 访问 redux 商店中可用的状态

标签: reactjs react-hooks use-effect


【解决方案1】:

抱歉,您的代码太复杂而无法阅读,请重新组织它以使其更具可读性和可理解性。请尝试将useSelector 线充到此线:

 const { auth, chat } = useSelector((state) => state);

这会导致多重渲染,因为useSelector 检测状态正在重新创建(使用扩展运算符),因此它会重新渲染组件。

在设置状态时加上useEffect 使用setState 回调,这不会覆盖您之前的状态更新:

setState(prev=>({...prev,newState}))

【讨论】:

  • 两者都做了,但重新渲染无限循环
  • @dPac 请发布一个代码沙箱来展示您的代码,以便我可以更好地帮助您
【解决方案2】:

useEffect 通常需要一个依赖数组。您在 useEffect 挂钩中使用的内容应该进入该数组,例如我们有一个设置 id 的函数。 useEffect 依赖项将需要数组中的 id。因此,只有在 id 发生变化时才更新/运行这个 useEffect 钩子。

useEffect(() => {
   setId(id)
}, [id])

如果您只想在第一次渲染时运行一次 useEffect,您可以将数组留空,如下所示:

useEffect(()=>{
  //http fetch request or something
}, [])

【讨论】:

  • 包含依赖数组后仍然出现错误,为了使useEffect作为componentDidMount工作,依赖数组必须为空
  • 我的猜测是您传播道具以设置状态的方式导致重新渲染。我认为添加一个条件语句只在 useEffect 内运行一次,然后将该条件传递给 useEffect 数组以停止将来的重新运行,这可能是让您的代码正常工作的快速技巧。 useEffect(()=>if(isFirst){setState();setIsFirst(false)},[isFirst])
  • 好的,让我试试
  • 你确实设置了一个空数组作为依赖数组?只需仔细检查,就像前面的第二个示例一样。
  • 是的,它是空的。但我也尝试了家属,但仍然失败
猜你喜欢
  • 2021-04-29
  • 2020-12-11
  • 2019-08-12
  • 1970-01-01
  • 2019-07-25
  • 2020-10-22
  • 2018-09-13
  • 2023-04-09
  • 2021-06-30
相关资源
最近更新 更多