state-management-riverpod

Enforces Riverpod 3.x ViewModel patterns with immutable state and unidirectional data flow in Flutter apps.

Updated Aug 22, 2026
One-click install
npx skills add https://github.com/zakariaf/NearlyStop --skill state-management-riverpod-zakariaf
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: state-management-riverpod
Source: https://github.com/zakariaf/NearlyStop/tree/main/.claude/skills/state-management-riverpod
Command: npx skills add https://github.com/zakariaf/NearlyStop --skill state-management-riverpod-zakariaf

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill includes scripts (resource) and references (resource) components.

What problem does it solve? Flutter feature state often drifts into mutable field bags, scattered loading flags, stale closures, and competing DI libraries, causing silent UI staleness and untestable code. This Skill standardizes feature state as one Notifier/AsyncNotifier/StreamNotifier ViewModel over an immutable value, with a single repository write path and Riverpod 3.x as the sole DI mechanism. ## Core Features & Use Cases - ViewModel conventions: One immutable state value per feature with value equality, private state mutated only through intent methods, derive-don't-store projections, and AsyncValue modeled exhaustively. - Riverpod 3.x guidance: Provider shape selection (StreamNotifier vs StreamProvider vs plain Provider), throwing-seam DI wired at the composition root, watch/read/listen/select read rules, family + autoDispose lifecycle, and a Provider/ChangeNotifier appendix for the official Flutter-guide stack. - CI enforcement: A ban-legacy-providers.sh script that fails builds on StateProvider/StateNotifierProvider/ChangeNotifierProvider, get_it, package:provider, Bloc, bespoke clocks, and raw DateTime.now() calls. - Use Case: When adding state to a new screen, writing a feature controller, or reviewing a PR for rebuild leaks, stale-closure captures, or disposal bugs, apply this Skill to get the correct provider shape, read pattern, and write path. ## Quick Start Ask the AI to add state management for a new Flutter feature screen using Riverpod 3.x following this skill's ViewModel and provider conventions.

Frequently Asked Questions about state-management-riverpod

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

FAQPage Schema
How do I structure feature state with Riverpod 3.x in Flutter?

Use one Notifier, AsyncNotifier, or StreamNotifier per feature exposing a single immutable state value with value equality. Widgets call intent methods like notifier.rename(id, name) and never mutate state directly; every transition assigns a new instance via copyWith.

When should I use ref.watch vs ref.read vs ref.listen in Riverpod?

Use ref.watch or ref.watch with .select inside build() for display, ref.read(p.notifier) inside callbacks like onTap to invoke intent methods, and ref.listen inside build() for one-shot side effects such as navigation or snackbars. Reading a value in build() freezes on stale data.

Is StateProvider still available in Riverpod 3.0?

StateProvider, StateNotifierProvider, and ChangeNotifierProvider are legacy in Riverpod 3.x and moved to package:flutter_riverpod/legacy.dart. The idiom is Notifier with NotifierProvider; the included CI script fails builds that import the legacy library.

Why does my Riverpod onTap callback act on stale data?

Capturing a ref.watch'ed value into an onTap closure freezes the previous entity, so a fast re-tap after rebuild acts on stale data with no lint warning. Pass a stable key like an id and resolve the entity at tap time via ref.read inside the intent method.

Can I use get_it or package:provider alongside Riverpod for DI?

No. Riverpod providers serve as the DI container: collaborators are plain Providers with throwing seams overridden once per flavor in main()'s ProviderScope. Mixing get_it, package:provider, or Bloc creates two competing state mechanisms and is banned by the CI gate.

How do I make time-dependent Riverpod state testable?

Inject package:clock's Clock through a clockProvider seam instead of calling DateTime.now(). Tests override it with clockProvider.overrideWithValue(Clock.fixed(t)) inside ProviderContainer.test(), making time-dependent behavior deterministic.