re-natal icon indicating copy to clipboard operation
re-natal copied to clipboard

Flickering components when not using dispatch-sync and reagent.core/flush

Open retrogradeorbit opened this issue 7 years ago • 4 comments

OK. This is not really a bug with re-frame, but an issue with React Native and Re-frame (and possibly normal react).

When I have a component, and on change I use a dispatch to alter the atom, and the value of the component is taken from a subscribe, when I change the component, the component flickers back and forth twice to get to the new value.

Lets say I have an input field. And the value of the field is "fooba", and I type "r". What I see in the component is fooba -> foobar -> fooba -> foobar.

After a bunch of digging what is happening is this:

  1. the component has the value 'fooba'.
  2. I type 'r'. The component itself is updated by react to 'foobar' and we see this change (no dispatch has been processed or atom has changed yet)
  3. react/reframe sees that the component is 'foobar' but the value it is set to is 'fooba', so it resets the component to 'fooba'
  4. the dispatch finally is processed, this sets the atom and the value to 'foobar' (but its not displayed yet)
  5. react/reframe sees the component state is fooba and should be foobar, and so sets it to foobar.

OK. changing the dispatch to a dispatch-sync is not enough to prevent this from happening. I have to use a dispatch-sync and then follow it with a reagent.core/flush, and then the flickering stops.

Here's some example code with a react native picker:

[picker {:style style-text
         :selected-value @(re-frame.core/subscribe [:picker-value])
         :on-value-change (fn [val index]
                                (re-frame.core/dispatch-sync [:set-picker-value val])
                                (reagent.core/flush))}
       [picker-item {:label "one" :value "one"}]
       [picker-item {:label "two" :value "two"}]]

So my question is, is this the best way to be doing this? Has anyone else experienced this? Is there a more elegant solution that doesn't involve the manual reagent.core/flush?

I have also asked this question on the re-frame issue tracker: https://github.com/Day8/re-frame/issues/368

retrogradeorbit avatar Jul 15 '17 14:07 retrogradeorbit