26

Is there a way I can kill/(get rid of) a timeout in reactjs?

setTimeout(function() {
//do something
}.bind(this), 3000);

Upon some sort of click or action, I want to be able to completely stop and end the timeout. Is there a way to do this? thanks.

3
  • 4
    it's still just JS, you do it the same way you'd do it without React. Commented Apr 8, 2015 at 22:57
  • clearTimeout will work assuming you store the timer id. Commented Apr 9, 2015 at 0:49
  • clear all timeouts can help Commented Oct 13, 2018 at 11:51

5 Answers 5

30

Assuming this is happening inside a component, store the timeout id so it can be cancelled later. Otherwise, you'll need to store the id somewhere else it can be accessed from later, like an external store object.

this.timeout = setTimeout(function() {
  // Do something
  this.timeout = null
}.bind(this), 3000)

// ...elsewhere...

if (this.timeout) {
  clearTimeout(this.timeout)
  this.timeout = null
}

You'll probably also want to make sure any pending timeout gets cancelled in componentWillUnmount() too:

componentWillUnmount: function() {
  if (this.timeout) {
    clearTimeout(this.timeout)
  }
}

If you have some UI which depends on whether or not a timeout is pending, you'll want to store the id in the appropriate component's state instead.

Sign up to request clarification or add additional context in comments.

4 Comments

There is a syntax error in the first code snippet, should be - setTimeout(function() { instead of setTimeout(function(), {
Do you need to set this.timeout = null in componentWillUnmount() after clearing it? Seems tidiest?
there is error in }.bind(this),, and this is an old syntax: componentWillUnmount: function() {
I've always wondered why people store some things in this (the component instance) and not in state. Because by that logic, why don't we store everything in this? Should I only store things that affect render in state, and the rest in this? If I wanted to store a count of ongoing parallel requests and only clear timeout when they're all completed, should I store that number in this as well? Does that have any downsides?
13

Since React mixins are now deprecated, here's an example of a higher order component that wraps another component to give the same functionality as described in the accepted answer. It neatly cleans up any remaining timeouts on unmount, and gives the child component an API to manage this via props.

This uses ES6 classes and component composition which is the recommended way to replace mixins in 2017.

In Timeout.jsx

import React, { Component } from 'react';

const Timeout = Composition => class _Timeout extends Component {
    constructor(props) {
      super(props);
    }

    componentWillMount () {
      this.timeouts = [];
    }

    setTimeout () {
      this.timeouts.push(setTimeout.apply(null, arguments));
    }

    clearTimeouts () {
      this.timeouts.forEach(clearTimeout);
    }

    componentWillUnmount () {
      this.clearTimeouts();
    }

    render () {
      const { timeouts, setTimeout, clearTimeouts } = this;

      return <Composition 
        timeouts={timeouts} 
        setTimeout={setTimeout} 
        clearTimeouts={clearTimeouts} 
        { ...this.props } />
    }
}

export default Timeout;

In MyComponent.jsx

import React, { Component } from 'react';
import Timeout from './Timeout';    

class MyComponent extends Component {
  constructor(props) {
    super(props)
  }

  componentDidMount () {
    // You can access methods of Timeout as they
    // were passed down as props.
    this.props.setTimeout(() => {
      console.log("Hey! I'm timing out!")
    }, 1000)
  }

  render () {
    return <span>Hello, world!</span>
  }
}

// Pass your component to Timeout to create the magic.
export default Timeout(MyComponent);

4 Comments

Wicked! Cheers @jmgem!
This is great! How would you pass MyComponent to Timeout if you are using redux's connect function?
Why do you have to go through all this? What is wrong with the answer of Jonny Buchannan?
does not work if i want to update a local state : this.props.setTimeout(() => { this.setState( {clicked: false}); }, 2000);
11

You should use mixins:

// file: mixins/settimeout.js:

var SetTimeoutMixin = {
    componentWillMount: function() {
        this.timeouts = [];
    },
    setTimeout: function() {
        this.timeouts.push(setTimeout.apply(null, arguments));
    },

    clearTimeouts: function() {
        this.timeouts.forEach(clearTimeout);
    },

    componentWillUnmount: function() {
        this.clearTimeouts();
    }
};

export default SetTimeoutMixin;

...and in your component:

// sampleComponent.js:
import SetTimeoutMixin from 'mixins/settimeout'; 

var SampleComponent = React.createClass({

    //mixins:
    mixins: [SetTimeoutMixin],

    // sample usage
    componentWillReceiveProps: function(newProps) {
        if (newProps.myValue != this.props.myValue) {
            this.clearTimeouts();
            this.setTimeout(function(){ console.log('do something'); }, 2000);
        }
    },
}

export default SampleComponent;

More info: https://facebook.github.io/react/docs/reusable-components.html

3 Comments

How would this translate to React using ES6 classes? Mixins are being deprecated soon.
For anyone wondering the same thing as @Scotty, I've submitted a 2017 version of the answer just below.
this is no longer up to date.
2

2023 Tested and working in production. This is the way I did it after this thread didn't provide me with an answer.

const MyComponent: React.FC<Props> = ({
  children,
  className = '',
}) => { 
  const timeoutRef = useRef<NodeJS.Timeout | null>(null)
  const [loaded, setLoaded] = useState(false)

  useEffect(() => {
    timeoutRef.current = setTimeout(
      () => setLoaded(true),
      10000
    )
    return () => {
      timeoutRef.current && clearTimeout(timeoutRef.current)
    }
    
  }, []) //eslint-disable-line

  const handleCancelTimeout = () => {
    timeoutRef.current && clearTimeout(timeoutRef.current)
  }

  return (
    <div>...</div>
  )
}

1 Comment

This is the most relevant way in 2024 for those who do not support legacy classes.
1

I stopped a setTimeout in my react app with Javascript only:

(my use case was to auto-save only after a clear 3 seconds of no keystrokes)

timeout;

handleUpdate(input:any) {
    this.setState({ title: input.value }, () => {

        clearTimeout(this.timeout);
        this.timeout = setTimeout(() => this.saveChanges(), 3000);

    });
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.