DEV Community

Zach Klippenstein
Zach Klippenstein

Posted on • Edited on • Originally published at blog.zachklipp.com

Plumbing data with derived state in Compose

This post has moved to blog.zachklipp.com.

Top comments (4)

The discussion has been locked. New comments can't be added.
Post has moved to https://blog.zachklipp.com/plumbing-data-with-derived-state-in-compose/
Collapse
 
gmk57 profile image
gmk57

Thanks for great "deep dive" series! Applying to typical Android apps:

State tracking works when reads are initiated from @Composable functions (not from e.g. onClick callbacks) and propagates through functions and computed properties, but not regular properties (e.g. adding backing field to _result in your From push to pull example breaks tracking).

Otherwise it's just a one-time read.

Is that understanding correct?

Looks convenient, but IMHO makes it harder to reason about code behavior. We can't say if a piece of code is "reactive" without looking above and below it in the call stack.

This is not a problem for UI code, but I'm thinking about using State in ViewModel & even deeper layers, so the call stack might be long.

Collapse
 
zachklipp profile image
Zach Klippenstein

State tracking works when reads are initiated from @Composable functions (not from e.g. onClick callbacks) and propagates through functions and computed properties, but not regular properties (e.g. adding backing field to _result in your From push to pull example breaks tracking).

Otherwise it's just a one-time read.

Is that understanding correct?

Yes.

Looks convenient, but IMHO makes it harder to reason about code behavior.

That can be true, there are definitely trade offs to this vs expressing reactivity in your types.

Collapse
 
easetheworld profile image
EaseTheWorld • Edited

Thank you for amazing post. I have a question about derivedState.
To understand more, I made a Conway Game of life with compose.
github.com/EaseTheWorld/game_of_li...
Which is simply,

  • Each cell is State<Boolean>
  • Cell of root gen(0) is MutableState<Boolean>. It is toggled by user click.
  • Cell of child gen(1,2,3...) are DerivedState<Boolean> of prev gen's 9 cells.

When I put one cell alive in gen0, I expected only gen1 is recalculated and gen2,3,4... are not
because their prev is caching and unchanged.(still dead)
But it turns out gen2,3,4... are all recalculated. I put log in ChildCell.calculate()

Did I miss something about caching logic in DerivedState?

I ran your WorksheetImpl in android emulator(Pixel 5 API 29) and got same behavior.
I changed first row from 31.50 to 31.5 and expected no calculation for later rows.
but evalResult is recalculated for each rows...

Any reply would be very helpful.

Collapse
 
startandroid profile image
Dmitry Pliskov • Edited

Thanks for your post!

I'm writing an article about side-effects and faced a question that I cannot answer.
What is difference between derivedStateOf and snapshotFlow.collectAsState?
Both of them observe states that they use. And both can help to reduce counts of recomposition