'Resolve "Can't perform a React state update on an unmounted component" Error

I have a question regarding how I can fix 'Can't perform a React state update' error message. I did read a little further into the issue and states it is only a warning. Please note, I'm a beginner at React. Here is the problem as follows. I have a header component that is comprised of a navbar that has two states for toggling the mobile navigation menu button and another for changing background-color on scroll. I implemented navbar toggle functionality and I started receiving the so-called error in JS console. Upon further inspection, I have determined that it is something to do with my toggle state. Any help will be appreciated. Thanks in advance!

import React, { useState } from 'react';
import { Icon } from 'react-icons-kit';
import {bars} from 'react-icons-kit/fa/bars';
import {times} from 'react-icons-kit/fa/times';
import {chevronCircleDown} from 'react-icons-kit/fa/chevronCircleDown';

const Header = (props) => {
    
const [toggle, setToggle] = useState(false);    
const [navbar, setNavbar] = useState(false); 
                                                 
   const handleToggle = () => {
       setToggle(!toggle);
      }                                           
       
   const changeBackground = () => {
          if(window.scrollY >= 60) {
               setNavbar(true);
          } 
          else {
              setNavbar(false);
          }
      }     
   
   window.addEventListener('scroll', changeBackground);

     

            if(props.data){
      var description = props.data.description;   
      var navigation = props.data.navigation.map(item => {
    return <li key={item.linkname} className="nav-item"><a href={item.href} className={item.className}>{item.linkname}</a></li> 
      });    
    }
                                                      
                                            
    return (
      <header id="home" className="main-header">                                         
           <div className="container">
              <nav className={navbar ? 'navbar nav-bg' : 'navbar'} aria-label="Main Navigation" id="navbar">
           <ul className={toggle ? 'navbar-nav active' : 'navbar-nav'} id="nav">
             {navigation}
           </ul>
           <button className="btn-mobile-nav" type="button" aria-controls="nav" aria-expanded={toggle ? 'true' : 'false'} aria-label="Mobile Navigation button" title="Mobile menu button" onClick={handleToggle}>{toggle ? <Icon icon={times} size={24} title="Close Menu"/> : <Icon icon={bars} size={24} title="Open Menu"/> }</button>
      </nav>
        </div>
               <div className="header-content d-flex flex-column">
           <div>
               <h1 className="header-title"><span className="typed"></span></h1>
               <p className="header-summary">{description}</p>
           </div>
       </div>
       <a href="#about" id="to-about" className="btn-up-down" title="Go to About" aria-label="Go to About section"> <Icon icon={chevronCircleDown} size={54}/></a>
   </header>
    );
    
}

export default Header;

import React from 'react';
import SkipNav from './Components/SkipNav';
import Header from './Components/Header';
import Footer from './Components/Footer';
import About from './Components/About';
import Resume from './Components/Resume';
import Portfolio from './Components/Portfolio';
import Contact from './Components/Contact';



class App extends React.Component {

  constructor(props){
    super(props);
    this.state = {   
      resumeData: [],
      recipName: '',
      recipEmail: '',
      recipSubject: '',
      recipMessage: ''    
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleCaptchaChange = this.handleCaptchaChange.bind(this);
    this.handleEmailSent = this.handleEmailSent.bind(this);  
  }

  getResumeData = () => {
   fetch('/data.json')
   .then(response => {
    return response.json()
   })
   .then(data => {
     this.setState({
       resumeData: data
     });
   })
   .catch(error => {
     console.log(error)  
     alert(`Unable to retrieve data! See JS console for details. Error:${error}`)
   })
   }
  
  handleChange = (event) => {
      this.setState({ [event.target.name]: event.target.value });
    }
  
  handleCaptchaChange = (value) => {
  console.log("Captcha value:", value);
}
  
  handleEmailSent = (event) => {
    
        event.preventDefault();
        if (this.state.recipName === '' || this.state.recipEmail === '' || this.state.recipSubject === '' || this.state.recipMessage === '') {
          console.log('All fields required!')
          alert('All fields are required!');
          return;
      }
    
     let data = {
      recipName: this.state.recipName,
      recipEmail: this.state.recipEmail,
      recipSubject: this.state.recipSubject,     
      recipMessage: this.state.recipMessage
    };
    console.log(data);
    
    
        fetch (`https://api.eahassan.me/sendEmail`, {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify(data)
    }).then((response) => {
        console.log(response.data);
        alert("E-Mail sent successfully!");
        window.location.reload();    
    })
    .catch((error) => console.log("E-Mail Failure - Error:", error));  
  }


  componentDidMount = () => {
    this.getResumeData(); 
  }

  render() {
      
      
      
    return (
        
       <div className="App">
          <SkipNav title="Skip to main content"/>
          <Header data={this.state.resumeData.main}/>
            <main id="mainContent">
              <About data={this.state.resumeData.main} title="About Me"/>
              <Resume data={this.state.resumeData.resume} eduTitle="Education" workTitle="Work" skillTitle="Skills"/>
              <Portfolio data={this.state.resumeData.portfolio}/>
              <Contact data={this.state.resumeData.main} recommendData={this.state.resumeData.recommendations} captchaChange={this.handleCaptchaChange} recipName={this.state.recipName} recipEmail={this.state.recipEmail} recipSubject={this.state.recipSubject} recipMessage={this.state.recipMessage} EmailSend={this.handleEmailSent} change={this.handleChange}/>
         </main>
         <Footer data={this.state.resumeData.main}/>
      </div> 
        
    );
  }
}

export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Error message



Solution 1:[1]

You are unconditionally adding a scroll event listener in the body of the component. This should be added in an useEffect hook and cleaned up when the component unmounts. For scroll events that are generally very noisy, you'll want to make these passive listeners.

useEffect(() => {
  const changeBackground = () => {
    setNavbar(window.scrollY >= 60);
  }
  window.addEventListener('scroll', changeBackground, { passive: true });

  return () => window.removeEventListener('scroll', changeBackground, { passive: true });
}, []);

  

Solution 2:[2]

The App component's constructor function was being rendered twice. I removed <React.StrictMode> from index.js and the error went away. Problem solved!

https://arange.github.io/2020-06-15-react-component-s-constructor-rendered-twice-leading-to-bugs-using-axios-interceptor/

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Drew Reese
Solution 2 Evan H.