Reputation: 864
I want to array items on after another. But it is only displaying the last element of the array.
Expected output is displaying "a" after 2 seconds "b" and so on.
class Main extends React.Component {
constructor(props) {
super(props)
this.state = {
role: ["a","b","c"],
display: "",
}
}
componentDidMount() {
for (let i of this.state.role) {
setTimeout(() => {
this.setState({ display: i})
}, 2000)
}
}
render() {
return (
<div>
<h3>{this.state.display}</h3>
</div>
)
}
}
ReactDOM.render(<Main />, 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: 2
Views: 2124
Reputation: 1941
The problem is that for (x of y)
runs directly and all three setTimeouts
created almost at once, then you see the result only of the last one cause they have 1-2 ms difference between them.
I used for (x in y)
instead to have the item index. Then I am using the item index to calculate its timeout based on its index.
This is my approach:
import React, { Component } from "react";
export default class Main extends Component {
constructor(props) { super(props);
this.state = {
role: ["a", "b", "c"],
display: ""
};
}
componentDidMount() {
for (let i in this.state.role) {
setTimeout(() => {
this.setState({
display: this.state.role[i],
});
}, 2000 * i);
}
}
render() {
return (
<>
<h3>{this.state.display}</h3>
</>
);
}
}
Upvotes: 0
Reputation: 2032
You can use way multiple the index
to create 3 different timeouts.
class Main extends React.Component {
constructor(props) {
super(props)
this.state = {
role: ["a","b","c"],
display: "",
}
}
componentDidMount() {
this.state.role.forEach((item, index) => {
setTimeout(() => {
this.setState({ display: item})
}, 2000*(index+1))
})
}
render() {
return (
<div>
<h3>{this.state.display}</h3>
</div>
)
}
}
ReactDOM.render(<Main />, 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
Reputation: 281646
The problem is that you are using a loop to create a timeout on componentDidMount. In such a case what would happen is that the loop will complete immedialtely creating 3 timers which resolve at nearly the same 2sec interval from the start and setState then batches all the three state update calls resulting in only the last one to be displayed.
In order to solve this you can make use of setInterval
like below
class Main extends React.Component {
constructor(props) {
super(props)
this.state = {
role: ["a","b","c"],
display: "",
}
}
componentDidMount() {
var index = 0;
this.timer = setInterval(() => {
this.setState({ display: this.state.role[index]});
index = (index + 1)%(this.state.role.length);
}, 2000)
}
componentWillUnmounnt() {
clearInterval(this.timer);
}
render() {
return (
<React.Fragment>
<h3>{this.state.display}</h3>
</React.Fragment>
)
}
}
ReactDOM.render(<Main />, 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"/>
Upvotes: 6