ugocasalone
ugocasalone

Reputation: 499

React render one element per second from array

On reactjs how does one print one element per second from an array? I have tried to replicate and simplify my work. The array comes from redux. But the final situation doesn't change. Thanks.

const arrWords=["I", "would", "like", "to", "print", "one", "word", "per", "second"];
class Message extends React.Component {
	renderWord(word,index) {
      return <span key={index}> {word} </span>;
    }
	renderWords() {
      const words =  arrWords.map((word, index) => {
      	return this.renderWord(word, index);
      });
      return words;
    }
    render(){
      return (
        <p>{this.renderWords()}</p>
      );
    }
};

ReactDOM.render(<Message  />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>

Upvotes: 1

Views: 334

Answers (3)

Deryck
Deryck

Reputation: 7658

The answers above aren't incorrect but they aren't very fun either.

Use Promise.resolve() to solve this.

not too sure if you mean render one word per second by replacing the previous each time, or one word per second by appending to the end

Replacing previous word

const arrWords=["I", "would", "like", "to", "print", "one", "word", "per", "second"];
class Message extends React.Component {
    state = { word: '', index: 0 };

    renderWord(word,index) {
      return new Promise(( resolve, reject ) => {
        if ( this.wordTimeout ) clearTimeout(this.wordTimeout);
        this.wordTimeout = setTimeout(() => 
          this.setState({ word, index }, resolve), 
          1000
        )
      });
    }

    componentDidMount () {
      arrWords.reduce(( promise, word, index ) => 
      	 promise.then(() => this.renderWord(word, index)), 
         Promise.resolve()
      );
    }

    render(){
      return (
        <p>
          <span key={this.state.index}> {this.state.word} </span>
        </p>
      );
    }
};

ReactDOM.render(<Message  />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>

Appending to create sentence

const arrWords=["I", "would", "like", "to", "print", "one", "word", "per", "second"];
class Message extends React.Component {
    state = { index: 0 };

    renderSentence (index) {
      return new Promise(( resolve, reject ) => {
        if ( this.wordTimeout ) clearTimeout(this.wordTimeout);
        this.wordTimeout = setTimeout(() => 
          this.setState({ index }, resolve), 
          1000
        )
      });
    }

    componentDidMount () {
      arrWords.reduce(( promise, word, index ) => 
      	 promise.then(() => this.renderSentence(index)), 
         Promise.resolve()
      );
    }

    render(){
      // Plenty of better ways to do this but this will do what you need
      const words = arrWords.slice(0, this.state.index + 1);
      const renderedWords = words.map(word => 
        <span key={`${this.state.index}-${word}`}> {word} </span>
      );
      return (
        <p>
          {renderedWords}
        </p>
      );
    }
};

ReactDOM.render(<Message  />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>

Upvotes: 1

canaan seaton
canaan seaton

Reputation: 6868

I think this should work for you. Use the React lifecycle methods to start and end an interval before the component mounts and unmount. Simply increment the index and let React handle the rest.

const arrWords = ["I", "would", "like", "to", "print", "one", "word", "per", "second"];

class Message extends React.Component {
    constructor() {
        super();

        this.state = {
            arr: arrWords,
            index: 0
        }
    }

    componentDidMount() {
        this.timer = setInterval(() => {
            const { index, arr } = this.state;

            // increment index if appropriate or reset to 0
            this.setState({ index: index + 1 >= arr.length ? 0 : index + 1});
        }, 1000);
    }

    // Clean up before unmounting
    componentWillUnmount() {
        clearInterval(this.timer);
    }

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

ReactDOM.render(<Message />, document.getElementById("app"));

Upvotes: 1

Shubham Khatri
Shubham Khatri

Reputation: 281646

One possible solution is to keep an index that keeps incrementing every second and render that many words

const arrWords=["I", "would", "like", "to", "print", "one", "word", "per", "second"];
class Message extends React.Component {
  state = {
     count: 0
  };
  componentDidMount() {
    this.timerID = setInterval(()=> {
      console.log(this.state);
      this.setState(prevState => ({
         count: (prevState.count + 1)%arrWords.length
      }))
    }, 1000);
  }
  componentWillUnmount() {
     clearInterval(this.timerID);
  }
	renderWord(word,index) {
      return <span key={index}> {word} </span>;
    }
	renderWords() {
      const words =  arrWords.map((word, index) => {
        if(index <= this.state.count)
      	  return this.renderWord(word, index);
      });
      return words;
    }
    render(){
      return (
        <p>{this.renderWords()}</p>
      );
    }
};

ReactDOM.render(<Message  />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="app"></div>

Upvotes: 3

Related Questions