deferring-state-reads

Migrates hot Jetpack Compose state reads from Composition to Layout or Draw phases using lambda modifiers.

Updated May 31, 2026
One-click install
npx skills add https://github.com/decoutkhanqindev/Lich-Viet-Loc-Phat --skill deferring-state-reads-decoutkhanqindev
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: deferring-state-reads
Source: https://github.com/decoutkhanqindev/Lich-Viet-Loc-Phat/tree/main/.claude/skills/deferring-state-reads
Command: npx skills add https://github.com/decoutkhanqindev/Lich-Viet-Loc-Phat --skill deferring-state-reads-decoutkhanqindev

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill includes references (resource) components.

What problem does it solve? Frequently-changing state (animation values, scroll positions, drag offsets) read in a composable body invalidates Composition on every frame, causing scroll jank, dropped frames, and full-subtree recomposition. This Skill identifies wrong-phase reads and rewrites them with lambda-based modifiers so only Layout or Draw re-runs per frame. ## Core Features & Use Cases - Value-to-lambda modifier migration: Converts Modifier.alpha(state.value), Modifier.offset(x.dp), and Modifier.background(color) into Modifier.graphicsLayer { }, Modifier.offset { IntOffset(...) }, and Modifier.drawBehind { } forms. - Lambda provider pattern: Rewrites hot values passed across composables as () -> T lambda providers so parent composables never recompose per frame. - Phase cheat sheet and verification: Provides a modifier-phase reference table plus Layout Inspector and @TraceRecomposition verification steps to confirm recomposition counts stop climbing. - Use Case: A scroll-driven sticky header recomposes the entire screen on every pixel of scroll; the Skill rewrites it as Modifier.offset { IntOffset(0, scrollState.value) } so only the header's Layout phase re-runs. ## Quick Start Ask the assistant to fix the per-frame recomposition in your composable by moving the animated alpha and scroll offset reads into lambda-based modifiers like Modifier.graphicsLayer and Modifier.offset.

Frequently Asked Questions about deferring-state-reads

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I stop Jetpack Compose from recomposing on every animation frame?▼

Move the state read out of the composable body into a lambda-based modifier such as Modifier.graphicsLayer { alpha = value } or Modifier.offset { IntOffset(x, y) }. The lambda reads state during Layout or Draw, so Composition is never invalidated per frame.

What is the difference between Modifier.offset(x.dp) and Modifier.offset { IntOffset }?▼

Modifier.offset(x: Dp, y: Dp) reads its arguments during Composition, invalidating the whole subtree when the value changes. Modifier.offset { IntOffset(...) } reads state during Layout, so only re-placement occurs and Composition is skipped.

Does Modifier.padding have a lambda form for animated insets?▼

No, Modifier.padding ships only value-based overloads, so it always reads in Composition. For hot inset state, write a custom Modifier.layout { measurable, constraints -> ... } block that reads the state during the Layout phase.

Why does my whole screen recompose when I scroll a LazyColumn?▼

Reading scrollState.value directly in a composable body subscribes the enclosing restart scope to per-pixel scroll updates. Wrap the read in Modifier.offset { IntOffset(0, scrollState.value) } or pass a () -> Float lambda provider to child composables.

When should I not use lambda-based modifiers for state reads?▼

Avoid them when state changes only once per user interaction, since the rewrite adds noise with no benefit. They also cannot help when the state decides which composable to emit, because lambda modifiers cannot change the composition tree.

How do I verify a Compose performance fix actually worked?▼

Check Layout Inspector or @TraceRecomposition in a release build on a real device and confirm the parent's recomposition count stays near zero per animation frame. Debug builds run interpreted and misrepresent actual rendering cost.