简体   繁体   中英

setState in ReactJS

I'm new to ReactJS and I can't seem to find out why the result of the following setState is not as I expect it to be (ie to increment the value every second by 1)

import React from 'react';
import ReactDOM from 'react-dom';

class Layout extends React.Component {

    constructor() {
        super();
        this.state = {
            name: "Behnam",
            i: 0
        }
    }

    render() {

        setInterval(() => {
            this.setState({ name : "Behnam" + this.state.i });
            this.setState({ i: this.state.i + 1 });
        }, 1000);

        return (
            <div className="container">
                {this.state.name}
            </div>
        );
    }
}

ReactDOM.render(<Layout />, document.getElementById('app'));

Instead the output string rapidly increases (I guess as fast as react is trying to keep its' virtual DOM updated). So I was wondering what is the right way to do this?

Every time you change the state, you rerender the component. Because you initiated the setInterval in the render method, you get another interval, which changes the state, and rerenders, and so on.

Move the setInterval to componentDidMount , which is invoked only once, when the component mounts:

import React from 'react';
import ReactDOM from 'react-dom';

class Layout extends React.Component {

    constructor() {
        super();
        this.state = {
            name: "Behnam",
            i: 0
        }
    }

    componentDidMount() { set the interval after the component mounted, and save the reference
        this.interval = setInterval(() => {
            this.setState({ 
                name: `Behnam${this.state.i}`, 
                i: this.state.i + 1
            });
        }, 1000);
    }

    componentWillUnmount() {
        this.interval && clearInterval(this.interval); // clear the interval when the component unmounts
    } 

    render() {
        return (
            <div className="container">
                {this.state.name}
            </div>
        );
    }
}

ReactDOM.render(<Layout />, document.getElementById('app'));

Currently, it is creating an interval every time the component is rendered, so there are multiple timers incrementing the value. You probably want to do it in componentDidMount() instead of render() . See docs .

import React from 'react';
import ReactDOM from 'react-dom';

class Layout extends React.Component {

    constructor() {
        super();
        this.state = {
            name: "Behnam",
            i: 0
        }
    }

    componentDidMount() {
        setInterval(() => {
            this.setState({ name : "Behnam" + this.state.i });
            this.setState({ i: this.state.i + 1 });
        }, 1000);
    }

    render() {
        return (
            <div className="container">
                {this.state.name}
            </div>
        );
    }
}

ReactDOM.render(<Layout />, document.getElementById('app'));

Every time a render is triggered, you're calling setInterval again, adding to the number of active intervals on the page.

You should perhaps make use of another lifecycle method, such as componentDidMount . You should remember to save the interval ID returned by setInterval , so that you can call clearInterval in componentWillUnmount .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM