渲染时错误的 setState() 调用以及可能的解决方案!

警告:在呈现其他组件(`BookingConfirmationModal`)时无法更新组件(`Bookings`)。要找到`BookingConfirmationModal`内错误的 setState() 调用,请按照所述跟踪堆栈!

在 React 应用程序中,您经常会遇到这个可怕的错误。当您尝试修改组件(Bookings)的状态时,就会出现此错误,该组件主要是父组件,而它正在渲染另一个组件(BookingConfirmationModal),该组件是子组件,并且您可能已将 setState() 函数作为 prop 传递给它。然而,这可能会导致应用程序的 UI 出现意外行为和不一致。

在这篇博客中,我将尝试指导您理解此错误、调试其来源并实施有效的解决方案,以防止它再次发生在您的 React 项目中。

理解错误

React 的渲染过程旨在高效且可预测。当组件的状态或属性发生变化时,React 会启动重新渲染过程。在此过程中,React 会遍历组件树,根据需要更新和重新渲染组件。“渲染时无法更新状态”错误的核心问题在于违反了这种可预测的渲染顺序。当一个组件试图在其自身的渲染阶段修改另一个组件的状态时,它会扰乱渲染周期并可能导致:

  • 无限循环:状态更新触发持续的重新渲染,可能会导致应用程序崩溃。
  • 不一致的 UI:UI 可能无法准确反映预期的状态变化。
  • 数据竞争:多个组件可能尝试同时修改相同的状态,从而导致不可预测的结果。
  • 可能的原因

  • 渲染阶段的状态更新:最可能的原因是您在渲染方法内部或在 BookingConfirmationModal 的渲染过程中调用 setState。
  • 渲染中的副作用:您可能会直接在渲染方法中执行副作用(例如获取数据或更新状态),这应该避免。
  • 解决方案

    要解决此问题,您应该确保在渲染阶段不会发生状态更新!您可以采取以下几个步骤:

  • 将状态更新移至 useEffect:如果您需要根据某些条件更新状态,请在组件渲染后使用 useEffect 钩子执行更新。
  • import React, { useEffect } from 'react';
    
    const BookingConfirmationModal = ({ someProp }) => {
      useEffect(() => {
        // Perform state updates here
        // Example: setState(someValue);
      }, [someProp]); // Add dependencies if needed
    
      return (
        
    {/* Your component JSX */}
    ); };
  • 避免在渲染中直接更新状态:确保您没有在渲染方法或渲染期间调用的任何函数中直接调用 setState。
  • 检查条件状态更新:如果您有更新状态的条件逻辑,请确保它不会在渲染阶段执行。
  • 检查您的 useMemo:如果您使用了 useMemo,请将其删除并在子组件中使用 useEffect,以便它在组件安装后运行,或者将 useMemo 移动到父组件。这将解决警告。
  • 一个可能的解决方案是 -

    import { useState, useEffect } from "react";
    import BookingConfirmationModal from "./BookingConfirmationModal";
    
    function App() {
      const [showModal, setShowModal] = useState(false);
      // other code
    
      return (
        

    This is app

    {showModal ? : null}
    ); } export default App; // BookingConfirmationModal.jsx const BookingConfirmationModal= ({ setTestingState }) => { useEffect(()=> { setTestingState(false) }, [setIsModalVisible]) //or other required dependencies return (
    // other codes
    ); }; export default BookingConfirmationModal;