state-management
<!-- Loaded by react-native-engineer when task involves useState, derived state, Zustand, state structure, dispatchers, ground truth -->
$ npx -y skills add notque/vexjoy-agent --agent claude-codeHow it fires
How this agent gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
Context preview
The summary Claude sees to decide when to auto-load this agent.
<!-- Loaded by react-native-engineer when task involves useState, derived state, Zustand, state structure, dispatchers, ground truth -->
Agent definition
state-management.mdState Management Reference
<!-- Loaded by react-native-engineer when task involves useState, derived state, Zustand, state structure, dispatchers, ground truth -->
Use Dispatch Updaters When Next State Depends on Current
**Impact:** MEDIUM — prevents stale closures
**Instead of:**
const onLayout = (e: LayoutChangeEvent) => {
const { width, height } = e.nativeEvent.layout
if (size?.width !== width || size?.height !== height) setSize({ width, height })
}**Use:**
const onLayout = (e: LayoutChangeEvent) => {
const { width, height } = e.nativeEvent.layout
setSize((prev) => {
if (prev?.width === width && prev?.height === height) return prev
return { width, height }
})
}For simple cases: `setCount((prev) => prev + 1)` instead of `setCount(count + 1)`.
Not needed for primitive state set to a new value directly.
---
Use Fallback State — undefined Means "User Hasn't Chosen Yet"
**Impact:** MEDIUM — reactive fallbacks, no stale initialState
**Instead of:**
const [enabled, setEnabled] = useState(defaultEnabled) // locks at mount
**Use:**
const [_enabled, setEnabled] = useState<boolean | undefined>(undefined)
const enabled = _enabled ?? defaultEnabled
// undefined = user hasn't touched it — falls back to parent prop
// Once user interacts, their choice persists
With server data:
const [_theme, setTheme] = useState<string | undefined>(undefined)
const theme = _theme ?? data.theme
---
Minimize State — Derive Values During Render
**Impact:** MEDIUM — fewer re-renders, no state drift
**Instead of:**
const [total, setTotal] = useState(0)
useEffect(() => { setTotal(items.reduce(...)) }, [items])**Use:**
const total = items.reduce((sum, item) => sum + item.price, 0)
const itemCount = items.length
State is the minimal source of truth. Everything else is derived.
---
State Must Represent Ground Truth
**Impact:** HIGH — single source of truth, easier debugging
State variables represent what is happening (`pressed`, `progress`, `isOpen`), not derived visuals (`scale`, `opacity`, `height`). Derive visuals from state.
**Instead of:**
const [isExpanded, setIsExpanded] = useState(false)
const [height, setHeight] = useState(0)
useEffect(() => { setHeight(isExpanded ? 200 : 0) }, [isExpanded])**Use:**
const [isExpanded, setIsExpanded] = useState(false)
const height = isExpanded ? 200 : 0
Same principle applies to Reanimated shared values — see `animation-patterns.md`.
---
Track Scroll Position in Shared Values or Refs
**Impact:** HIGH — prevents render thrashing during scroll
Scroll events fire 60/s. `useState` for scroll position = re-render every frame = dropped frames.
**Instead of:**
const [scrollY, setScrollY] = useState(0)
const onScroll = (e) => setScrollY(e.nativeEvent.contentOffset.y)
**Use (Reanimated for scroll-driven animations):**
const scrollY = useSharedValue(0)
const onScroll = useAnimatedScrollHandler({
onScroll: (e) => { scrollY.value = e.contentOffset.y }
})
return <Animated.ScrollView onScroll={onScroll} scrollEventThrottle={16} />**Use (ref for non-reactive tracking):**
const scrollY = useRef(0)
const onScroll = (e) => { scrollY.current = e.nativeEvent.contentOffset.y }Read more
State Management Reference
<!-- Loaded by react-native-engineer when task involves useState, derived state, Zustand, state structure, dispatchers, ground truth -->
Use Dispatch Updaters When Next State Depends on Current
**Impact:** MEDIUM — prevents stale closures
**Instead of:**
const onLayout = (e: LayoutChangeEvent) => {
const { width, height } = e.nativeEvent.layout
if (size?.width !== width || size?.height !== height) setSize({ width, height })
}**Use:**
const onLayout = (e: LayoutChangeEvent) => {
const { width, height } = e.nativeEvent.layout
setSize((prev) => {
if (prev?.width === width && prev?.height === height) return prev
return { width, height }
})
}For simple cases: `setCount((prev) => prev + 1)` instead of `setCount(count + 1)`.
Not needed for primitive state set to a new value directly.
---
Use Fallback State — undefined Means "User Hasn't Chosen Yet"
**Impact:** MEDIUM — reactive fallbacks, no stale initialState
**Instead of:**
const [enabled, setEnabled] = useState(defaultEnabled) // locks at mount
**Use:**
const [_enabled, setEnabled] = useState<boolean | undefined>(undefined) const enabled = _enabled ?? defaultEnabled // undefined = user hasn't touched it — falls back to parent prop // Once user interacts, their choice persists
With server data:
const [_theme, setTheme] = useState<string | undefined>(undefined) const theme = _theme ?? data.theme
---
Minimize State — Derive Values During Render
**Impact:** MEDIUM — fewer re-renders, no state drift
**Instead of:**
const [total, setTotal] = useState(0)
useEffect(() => { setTotal(items.reduce(...)) }, [items])**Use:**
const total = items.reduce((sum, item) => sum + item.price, 0) const itemCount = items.length
State is the minimal source of truth. Everything else is derived.
---
State Must Represent Ground Truth
**Impact:** HIGH — single source of truth, easier debugging
State variables represent what is happening (`pressed`, `progress`, `isOpen`), not derived visuals (`scale`, `opacity`, `height`). Derive visuals from state.
**Instead of:**
const [isExpanded, setIsExpanded] = useState(false)
const [height, setHeight] = useState(0)
useEffect(() => { setHeight(isExpanded ? 200 : 0) }, [isExpanded])**Use:**
const [isExpanded, setIsExpanded] = useState(false) const height = isExpanded ? 200 : 0
Same principle applies to Reanimated shared values — see `animation-patterns.md`.
---
Track Scroll Position in Shared Values or Refs
**Impact:** HIGH — prevents render thrashing during scroll
Scroll events fire 60/s. `useState` for scroll position = re-render every frame = dropped frames.
**Instead of:**
const [scrollY, setScrollY] = useState(0) const onScroll = (e) => setScrollY(e.nativeEvent.contentOffset.y)
**Use (Reanimated for scroll-driven animations):**
const scrollY = useSharedValue(0)
const onScroll = useAnimatedScrollHandler({
onScroll: (e) => { scrollY.value = e.contentOffset.y }
})
return <Animated.ScrollView onScroll={onScroll} scrollEventThrottle={16} />**Use (ref for non-reactive tracking):**
const scrollY = useRef(0)
const onScroll = (e) => { scrollY.current = e.nativeEvent.contentOffset.y }Essays and writing behind this toolkit live at vexjoy.com. AI agents skip steps. "Looks correct" replaces running tests. "Trivial change" replaces verification.
Repo: notque/vexjoy-agent
Other agents on vexjoy-agent.
- ansible-automation-engineer
Ansible automation: playbooks, roles, collections, Molecule testing, Vault security.
Open agent - modules
**Scope**: Module selection patterns, builtin vs command/shell decisions, collection modules, and version-specific module changes **Version range**: ansible-core 2.14+ / Ansible Collections (community.general 7.0+) **Generated**: 2026-04-04 — verify against current Ansible
Open agent - testing
**Scope**: Molecule test scenarios, ansible-lint rules, idempotency validation, and check-mode patterns **Version range**: Molecule 6.0+ / ansible-lint 6.0+ / ansible-core 2.14+ **Generated**: 2026-04-04 — verify against current Molecule and ansible-lint documentation
Open agent - base-instructions
Universal operational rules injected by /do at agent dispatch. Domain-specific rules live in each agent's .md file.
Open agent - communication-patterns
**Scope**: Failure modes in agent output style — over-reporting, self-congratulation, verbose narration, and hedging. Covers what to detect and how to fix each. **Version range**: all versions **Generated**: 2026-05-11
Open agent - combat-effects-upgrade
Zero-dependency combat visual upgrades: CSS particle replacement, Framer Motion combat juice, CSS 3D card transforms.
Open agent

