Reputation: 3809
I have a React application in which multiple sequential CPU intensive tasks happen. I would like to track the progress of the overall operation.
class Hello extends React.Component {
constructor() {
super()
this.state = {
status: 'not started'
}
this.handler = this.handler.bind(this)
}
componentDidUpdate() {
if(this.state.status === 'starting') {
this.cpuIntensive()
this.setState({status: 'first task done'})
}
if(this.state.status === 'first task done') {
this.cpuIntensive()
this.setState({status: 'second task done'})
}
if(this.state.status === 'second task done') {
this.cpuIntensive()
this.setState({status: 'finished'})
}
}
cpuIntensive() {
let result = 0
for (var i = Math.pow(7, 8); i >= 0; i--) {
result += Math.atan(i) * Math.tan(i);
}
}
handler() {
this.setState({status: 'starting'})
}
render() {
return (
<div>
<div>{this.state.status}</div>
<button onClick={this.handler}>START</button>
</div>
)
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<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="container"></div>
In this snippet when you click START
the state will indeed change, we go through componentDidUpdate
but the component do not re-render.
To make it work like I want, I can do:
class Hello extends React.Component {
constructor() {
super()
this.state = {status: 'not started'}
this.handler = this.handler.bind(this)
}
componentDidUpdate() {
if(this.state.status === 'starting') {
setTimeout(() => {
this.cpuIntensive()
this.setState({status: 'first task done'})
}, 100)
}
if(this.state.status === 'first task done') {
setTimeout(() => {
this.cpuIntensive()
this.setState({status: 'second task done'})
}, 100)
}
if(this.state.status === 'second task done') {
setTimeout(() => {
this.cpuIntensive()
this.setState({status: 'finished'})
}, 100)
}
}
cpuIntensive() {
let result = 0
for (var i = Math.pow(7, 8); i >= 0; i--) {
result += Math.atan(i) * Math.tan(i);
}
}
handler() {
this.setState({status: 'starting'})
}
render() {
return (
<div>
<div>{this.state.status}</div>
<button onClick={this.handler}>START</button>
</div>
)
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<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="container"></div>
It looks bad IMO. I'm looking for alternatives :)
Thank you for your time.
EDIT: web workers are not an option
Upvotes: 1
Views: 350
Reputation: 3046
You could start your operation in your handler
, and use setTimeout()
to chain / allow for renders to happen in between. Then you would not need to use the react state for starting those consecutive operations.
Another option would be to use a WebWorker.
Upvotes: 1