2

I am performing a tasks that takes a few seconds to complete and am trying to show an animated progress indicator. When attempting to set the state to update the indicator, it only updates after the task has been completed.

I have tried using callbacks to accomplish this, but it doesn't seem to be working.

import React, { Component } from 'react'
import { Lion as Button } from 'react-button-loaders'

class xx extends Component {
  constructor(props){
  super(props)
  this.state = {
    buttonState: ''
  }

this.handleClick = this.handleClick.bind(this)
}

Test(){
  // Do task that takes some time
  this.setState({buttonState: 'finished'} // End animation
}

handleClick() {
  this.setState({buttonState: 'loading'},
  () => {
    this.Test()
  })
}
  render() {
    return (
      <div>
        <Button onClick={this.handleClick} state={this.state.buttonState}>Test
        </Button>
      </div>
    );
  }
}

export default xx;

Without setting the state to finished, the activity indicator only appears after the entire task has already completed.

  • And probably you're getting an error in the console. See that question: https://stackoverflow.com/q/31045716/863110 – Mosh Feu Jun 25 '19 at 14:44
  • Updated the code, copied over the wrong editor @MoshFeu –  Jun 25 '19 at 14:49
  • 1
    You're missing the task code, it's not hard to do - setState after the task is complete. Since that code is missing that's all I can say. You also don't need to wait on the state change before starting the task. – Dominic Jun 25 '19 at 14:51
  • 1
    That still doesn't make sense to me, if your task is so fast that the animation doesn't have time to run then what's the problem? Why would you want to artificially slow down your task to show an animation? Anyway it's your UX! – Dominic Jun 25 '19 at 14:58
  • I'm not sure again when exactly you want to hide the animation? – Mosh Feu Jun 25 '19 at 15:08
  • Updated code, right after the task in Test() @MoshFeu –  Jun 25 '19 at 15:11
  • If I understand you correctly, the `Task` contains a lot of work. So you want to hide the indicator *before* the heavy code is firing? – Mosh Feu Jun 25 '19 at 15:39

1 Answers1

1

The fastest way that comes in my mind to make it not-blocking is to take advantage of setTimeout():

function Test(param) {
    setTimeout((param) => { /* ...code */ }, 1000);
}
Mosè Raguzzini
  • 15,399
  • 1
  • 31
  • 43
  • 2
    This may work, but it isn't very "react like" way of doing it. – alexr89 Jun 25 '19 at 15:02
  • @alexr89 what would be? –  Jun 25 '19 at 15:04
  • @alexr89 there are a LOT of way to make non-blocking code. This is perfectly legit also in react. – Mosè Raguzzini Jun 25 '19 at 15:09
  • setTimeout is very error prone, what if it takes 1 millisecond to return - having the user sit for 1000 is not good. What if it takes 2000 to return - you will get the wrong result? In my opinion you should have a "loading" state value, which you set to false on mount, and then to true when Test is called.While "loading" is true, have a spinner or some UI indication that its loading, and then set "loading" to false again when you set "buttonState" in Test. Happy to write a code answer if you'd like. – alexr89 Jun 26 '19 at 12:22
  • @alexr89 for non-blocking function also 0ms works, and this is the most common pattern to avoid blocking functions in JS. You do not understand what this code implies. Cheers. – Mosè Raguzzini Jun 26 '19 at 12:54