Dave Cook
Dave Cook

Reputation: 717

React: SetInterval in ComponentDidMount causing error "Warning: Can't perform a React state update on an unmounted component."

I want to add a typing effect to a component in my React app and I'm using setInterval to do this. Everything works fine but I'm getting the following error:

Warning: Can't perform a React state update on an unmounted component. 
This is a no-op, but it indicates a memory leak in your application. 
To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method

The function starts in componentDidMount() so I don't understand why it's saying that I'm updating an unmounted component. I've tried to add clearInterval() in componentWillUnmount() but the error still shows.

Code:

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

componentWillUnmount(){
    console.log(this.state.intervalId);
    clearInterval(this.state.intervalId);
}

typeText = () => {
    const sp = (text,key) => <span key={key} style={{whiteSpace: 'pre-line'}}>{text}</span>;
    const results = this.state.screenText;
    let start = 0;
    let cursor = 0;
    const intervalId = setInterval(() => {
        if (results.length) results.pop();
        const str = this.state.text.slice(start,cursor);
        const span = sp(str,cursor);
        results.push(span);
        this.setState({screenText:results});
        start = Math.floor((cursor / 80));
        cursor += 1;
        if (cursor > this.state.text.length) clearInterval(intervalId);  
    },5);

    this.setState({intervalId: intervalId});       
    console.log(this.state.intervalId);  
}
render() {
    return <span id="typing"> {this.state.screenText}</span> 
}

Upvotes: 1

Views: 296

Answers (1)

Shahab Emami
Shahab Emami

Reputation: 324

I think the problem with your code is that you are saving intervalId in the state of the component.
As you probably know when you call setState it causes rerender.
you can save your intervalId in the attribute of class.
please consider these changes in your code:

  1. Define an attribute in your class like this
    class MyClsss extends React.component{
      intervalId = "";
        ...
    }
    
  2. Save your interval id in this attribute like this
    this.intervalId = setInterval(...)
    
  3. Clear your interval wherever you want this way
    clearInterval(this.intervalId);
    

Upvotes: 2

Related Questions