techKid-Rinshad
techKid-Rinshad

Reputation: 197

How to render a component every three seconds?

import react, {Component} from 'react';

class Test extends component {
    constructor() {
        this.super();
        this.state = {
            message: [1, 2, 3, 4, 5]
        }
    }

    render() {
        return(
            <p>this.state.message</p>
        )
    }
}

How can I render the items in the state 'message' one by one after every three seconds? The desired output on the browser is the following:

1 2 3 4 5

each of the above items appears after three seconds. for example: display 1, then display '...' for three seconds to indicate loading, then display 2, then '...' for three seconds and so on. Thank you so much for your inputs in advance!

Upvotes: 0

Views: 2984

Answers (4)

falinsky
falinsky

Reputation: 7428

You can try to use setTimeout to have control over the minimum time after now when you want to run something.

class Test extends React.Component {
    constructor(props) {
        super(props);

        this.timeout = 3000;
        this.availableMessages = [1, 2, 3, 4, 5];
        this.state = {
            itemsToShow: [],
            showLoader: false,
        };
    }

    processNextItem = () => {
      const item = this.getItemToShow();
      
      if (item) {
        this.setState({showLoader: true});

        setTimeout(() => {
          this.setState({showLoader: false});
          this.addItemToShow(item, this.processNextItem);
        }, this.timeout);
      }
    }

    getItemToShow = () => this.availableMessages.shift();

    addItemToShow = (item, onAdd) => {
      this.setState(({itemsToShow}) => ({
        itemsToShow: itemsToShow.concat(item)
      }), onAdd);
    }

    componentDidMount() {
      this.addItemToShow(this.getItemToShow());
      this.processNextItem();
    }

    render() {
        return (
           <div>
              {this.state.itemsToShow.map((item, index) => (
                <span key={index}>{item} </span>
              ))}
              {this.state.showLoader && '...'}
           </div>
        )
    }
}

ReactDOM.render(<Test />, document.getElementById('root'));
<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>
<div id="root"></div>

Upvotes: 0

Solo
Solo

Reputation: 6957

Here is an alternative take on it.

You need to introduce some new state to toggle between number and ..., e.g isLoading.

componentDidMount() {
   this.interval = setInterval(() => {
      this.setState(state => {
        if (state.message.length < 2) {
          clearInterval(this.interval);
          return null;
        }

        let newState = [...state.message];
        newState.shift();
        return {message: newState};
      });
   }, 3000);
}

render() {
  return(
    <p>{this.state.message[0]}</p>
  );
}

Upvotes: 1

im_tsm
im_tsm

Reputation: 2051

You could use componentDidMount lifecycle hook and setInterval to achieve the result.

Here is working codesandbox

P.S. As t-j-crowder already mentioned in his answer it is very similar to the example in Reactjs documentation.

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074138

It's very similar to this example in the React documentation. Save the index of the current message in state, starting with 0, and then in componentDidMount use setInterval to call setState to increment it (wrapping around if you want to do that, or stopping when you reach the end if you want to do that).

Also:

  • Correct your extends clause: Component should be capitalized.
  • You should pass on the arguments to constructor to super.
  • this.super() shouldn't have this on it.

Something like this (this one keeps going, instead of stopping):

const { Component } = React;

class Test extends Component {
    constructor(...args) {
        super(...args);
        this.state = {
            messages: [1, 2, 3, 4, 5],
            index: 0
        };
    }
    
    componentDidMount() {
      this.timer = setInterval(() => {
        this.setState(({messages, index}) => {
          index = (index + 1) % messages.length;
          return {
            index
          };
        });
      }, 3000); // 3000ms = three seconds
    }

    render() {
        const { index, messages } = this.state;
        return(
            <p>{messages[index]}</p>
        );
    }
}

ReactDOM.render(
  <Test />,
  document.getElementById("root")
);
<div id="root"></div>

<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>

Re:

constructor(...args) {
    super(...args);
    // ...
}

You'll see people doing this instead a lot, and they do this in the React documentation as well:

constructor(props) {
    super(props);
    // ...
}

That only passes on the first argument. Early on I got in the habit of passing them all along, but I guess the React team probably won't add more arguments to the standard constructor call given how much code follows the example that only passes on the first...

Upvotes: 4

Related Questions