0

I have a timer on my web app on the home component, that is doing some countdown. Here's the Home component:

export default class Home extends React.Component {

    timer() {
        var countDownDate = new Date("Sep 5, 2018 15:37:25").getTime();
        var x = setInterval(() => {

            var now = new Date().getTime();

            var distance = countDownDate - now;

            var days = Math.floor(distance / (1000 * 60 * 60 * 24));
            var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
            var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
            var seconds = Math.floor((distance % (1000 * 60)) / 1000);

            document.getElementById("timer").innerHTML = days + "d " + hours + "h "
                + minutes + "m " + seconds + "s ";

            if (distance < 0) {
                clearInterval(x);
                document.getElementById("timer").innerHTML = "EXPIRED";
            }
        }, 1000);
    }

    componentDidMount() {
        $('.monster').fadeIn('slow');
        this.timer();
    }


    render() {
        return (
            <div id="timer"></div>
        )
    }
}

Here's my Questions component:

export default class AssignmentsComponent extends React.Component {
    render() {
        return (
            <h1>Questions Component</h1>
        )
    }
}

This is my App.js component:

export default class App extends Component {
    render() {
        return (
            <div className="App">
                <NavigationComponent {...this}/>
                {/*<CheckIfHasCurrentTasksComponent user={firebase.auth().currentUser}/>*/}
                {/*{this.state.user ? <Questions/> : <Home/>}*/}
            </div>
        );
    }
}

And just in case it matters this is my Navigation component:

export default class NavigationComponent extends React.Component {

    render() {
        return (
            <BrowserRouter>
                <React.Fragment>
                    <Navbar className="fixedTop custom_navbar half_transparent">
                        <Nav className="float_right">
                            <NavItem className="custom_button_navbar"><span>pobierz</span></NavItem>

                            {
                                firebase.auth().currentUser !== null ?
                                    <React.Fragment>
                                        <LinkContainer id="assignments" to='/assignments'>
                                            <NavItem>Zadania</NavItem>
                                        </LinkContainer>
                                        <NavItem onClick={logout.bind(this)}>Wyloguj się</NavItem>
                                    </React.Fragment>
                                    :
                                    <NavItem onClick={this.openLogin}
                                             className="custom_button_navbar"><span>Zaloguj się</span></NavItem>
                            }

                        </Nav>
                    </Navbar>
                    <Switch>
                        <Route exact path="/assignments" render={
                            () => (firebase.auth().currentUser === null ?
                                <Redirect to='/'/> : <AssignmentsComponent/>)
                        }/>

                        <Route exact path='/assignment/:id' render={
                            props => (
                                firebase.auth().currentUser === null ?
                                    <Redirect to='/'/> : <CheckIfHasCurrentTasksComponent {...props}/>
                            )
                        }/>

                        <Route exact path="/" component={HomeComponent}/>
                    </Switch>
                    <LoginFormComponent show={this.state.show} changeShowState={this.changeShowState}/>
                </React.Fragment>
            </BrowserRouter>
        )
    }
}

What the problem is: When I open home component, all goes well, the timer fires up, and it's all pretty. But if I go to questions component, the timer() method is still trying to run, even though I didn't call it anywhere in the Assignments component. That's when the app crashes.

Adding a try catch block inside the timer() method like this:

try {
    document.getElementById("timer").innerHTML = days + "d " + hours + "h "
        + minutes + "m " + seconds + "s ";

    if (distance < 0) {
        clearInterval(x);
        document.getElementById("timer").innerHTML = "EXPIRED";
    }
} catch (e) {

}

Solves the issue, but I'm pretty sure it's a bad practice.

So how can I make it only be called when the Home component is being rendered?

Alex Ironside
  • 4,658
  • 11
  • 59
  • 119

1 Answers1

2

You should remove the timer when the component unmounts. You can do this in the Home component's componentWillUnmount() life cycle method.

See:

https://reactjs.org/docs/react-component.html#componentwillunmount

Stop setInterval call in JavaScript

Winter
  • 2,407
  • 1
  • 19
  • 28