2

I need to propagate state changes to user screen as quickly as possible for some important UI elements, defer other element renderring a bit.

I know about setState's callback, it doesn't help me here. I think fiber priorities could help me, but I don't know how to use them.

Example:

I have a button that must be disabled immediately after click. I also have many other slow components that change on that button click.

React batches rendering of the disabled button and other slow components together so the button does not get disabled immediately.

Current workaround is to delay other state changes, to make React immediately disable the button, and only then start to modify other components:

this.setState({ enabled: false }, () => {
    this.debounce = setTimeout(() => {
        this.props.onModified(value);
    }, 200);
})

Is there some explicit way to tell React to be fast to render in some important state changes, without batching them?

(The problem is not only with buttons, but with immediate closing of the modal dialogs as well)

https://codesandbox.io/s/kk4o612ywr

xiety
  • 304
  • 6
  • 17
  • Possible duplicate of [Calling functions after state change occurs in reactjs](https://stackoverflow.com/questions/45992682/calling-functions-after-state-change-occurs-in-reactjs) – GalAbra Dec 19 '18 at 09:13
  • @GalAbra doesn't seems to be a duplicate question, the purpose is quite different. – Just code Dec 19 '18 at 09:30

1 Answers1

1

You can use callback function of the setstate, something like this, which will ensures the rendering of the first change. so, your button will get the disabled first and then you can update your state with different operations. using timeout will not be accurate as there is fixed timing which will cause the inaccurate results.

Here is what I did:

  this.setState({ enabled1: false },function(){     
      this.setState(prevState => ({ data: prevState.data + 1 }));
    });  

Demo

Just code
  • 13,553
  • 10
  • 51
  • 93
  • But in your example the button does not get disabled immediately. It works as slow as in my original sandbox. And as you can see in my example, I already use callback in my setState function, but I still need to add setTimeout to separate renders. – xiety Dec 19 '18 at 11:02
  • @xiety yes, but using callback ensures the button disability first and then it will do the rest work, this way you do not have to worry about getting second click. So, What are you worried about? if you still want to take an effect immediately, I am afraid you will have to go with the `e.target.disabled = true` inside click. – Just code Dec 19 '18 at 11:07
  • So the best way is to manipulate DOM directly? React tries to increase performance using batch, ruining the user experience in some cases. I need a way to disable this optimizations. Or to add some priorities to state changes. – xiety Dec 19 '18 at 11:13
  • @xiety What do you mean by priorities? you are ensuring the button disablitiy by using the callback and then you are calling the second state, because, the state change is async you are noticing some visual changes to ui. check console.log in my demo. – Just code Dec 19 '18 at 11:16
  • I'm trying to make my page more responsive to user interactions. If the user clicks a button, it must be disabled visually at the same time. Not depending on several heavy grids that I also rerender on that click. With more grids the less button is visually responsive. And setTimout helps me, but looks awkward. And 200 ms was chosen by hand, and may not work in other browsers. In fibers there are priorities for async rerender, but they are used only internally, afaik. – xiety Dec 19 '18 at 11:27
  • @xiety I understand your concern, as far as I know there is not way in react, you need to use fibers instead, I will look for an alternative if I can help. – Just code Dec 19 '18 at 11:29