[{"data":1,"prerenderedAt":76},["ShallowReactive",2],{"tutorial-gestire-lo-stato-in-flutter-con-riverpod-guida-pratica":3,"comments-tutorial-gestire-lo-stato-in-flutter-con-riverpod-guida-pratica":75},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"video_url":10,"difficulty":11,"estimated_minutes":12,"flutter_version":13,"status":14,"published_at":15,"meta_title":16,"meta_description":17,"category":18,"author":22,"steps":24},15,"Gestire lo stato in Flutter con Riverpod: guida pratica","gestire-lo-stato-in-flutter-con-riverpod-guida-pratica","Impara a usare Riverpod per gestire lo stato della tua app Flutter in modo dichiarativo, testabile e disaccoppiato dal BuildContext.","Riverpod è una libreria di gestione dello stato moderna, evoluzione spirituale di Provider, creata dallo stesso autore. A differenza di Provider, Riverpod non dipende dal `BuildContext`, è completamente type-safe e gestisce in modo elegante stati asincroni e dipendenze tra provider.\n\nIn questo tutorial costruiremo un piccolo contatore e poi una schermata che carica dati in modo asincrono, utilizzando i generatori di codice di `flutter_riverpod` e `riverpod_annotation`. Al termine saprai dichiarare provider, leggere e modificare lo stato e gestire i casi di caricamento ed errore.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F649ff6a1-1f63-4d24-a984-f71315d162d1.jpg",null,"intermediate",35,"3.x","published","2026-06-22T07:29:49+00:00","Gestire lo stato in Flutter con Riverpod","Guida pratica a Riverpod in Flutter: provider, NotifierProvider e stati asincroni con AsyncValue, passo dopo passo.",{"id":19,"name":20,"slug":21},1,"Guide","guide",{"id":19,"name":23},"Flutter Bot",[25,32,40,47,54,61,68],{"id":26,"position":19,"title":27,"body":28,"code_snippet":29,"code_language":30,"expected_result":31,"demo_url":10,"video_url":10},104,"Installare le dipendenze","Aggiungiamo `flutter_riverpod` per il runtime e, opzionalmente, `riverpod_annotation` insieme ai generatori di codice per uno stile più conciso e moderno.\n\nEsegui questi comandi nella root del progetto:","flutter pub add flutter_riverpod riverpod_annotation\nflutter pub add dev:riverpod_generator dev:build_runner dev:custom_lint dev:riverpod_lint","bash","Le dipendenze vengono aggiunte al file pubspec.yaml senza errori.",{"id":33,"position":34,"title":35,"body":36,"code_snippet":37,"code_language":38,"expected_result":39,"demo_url":10,"video_url":10},105,2,"Avvolgere l'app con ProviderScope","Tutti i provider di Riverpod vengono memorizzati in un `ProviderScope`. Deve essere il widget radice dell'applicazione: senza di esso i provider non funzionano.","import 'package:flutter\u002Fmaterial.dart';\nimport 'package:flutter_riverpod\u002Fflutter_riverpod.dart';\n\nvoid main() {\n  runApp(\n    const ProviderScope(\n      child: MyApp(),\n    ),\n  );\n}\n\nclass MyApp extends StatelessWidget {\n  const MyApp({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return const MaterialApp(\n      home: CounterPage(),\n    );\n  }\n}","dart","L'app si avvia normalmente: ora l'intero albero dei widget ha accesso ai provider.",{"id":41,"position":42,"title":43,"body":44,"code_snippet":45,"code_language":38,"expected_result":46,"demo_url":10,"video_url":10},106,3,"Creare un Notifier per il contatore","Usiamo l'annotazione `@riverpod` per generare un `NotifierProvider`. Il metodo `build` restituisce lo stato iniziale, mentre i metodi pubblici permettono di modificarlo aggiornando `state`.\n\nSalva il file come `counter.dart`. La parte `part 'counter.g.dart';` è necessaria al generatore di codice.","import 'package:riverpod_annotation\u002Friverpod_annotation.dart';\n\npart 'counter.g.dart';\n\n@riverpod\nclass Counter extends _$Counter {\n  @override\n  int build() => 0; \u002F\u002F stato iniziale\n\n  void increment() => state = state + 1;\n  void decrement() => state = state - 1;\n  void reset() => state = 0;\n}","Il file è pronto, ma servirà generare il codice nel passo successivo.",{"id":48,"position":49,"title":50,"body":51,"code_snippet":52,"code_language":30,"expected_result":53,"demo_url":10,"video_url":10},107,4,"Generare il codice con build_runner","Il generatore crea il file `*.g.dart` con il provider `counterProvider`. Lancia il comando una volta, oppure tienilo in watch durante lo sviluppo per la rigenerazione automatica.","dart run build_runner watch -d","Viene creato il file counter.g.dart e l'identificatore counterProvider diventa disponibile.",{"id":55,"position":56,"title":57,"body":58,"code_snippet":59,"code_language":38,"expected_result":60,"demo_url":10,"video_url":10},108,5,"Consumare lo stato in un widget","Per leggere i provider all'interno di un widget usiamo `ConsumerWidget` (o `ConsumerStatefulWidget`), che fornisce un oggetto `WidgetRef`.\n\n- `ref.watch(provider)` osserva lo stato e ricostruisce il widget quando cambia.\n- `ref.read(provider.notifier)` ottiene il Notifier per invocare i metodi senza ricostruire.","import 'package:flutter\u002Fmaterial.dart';\nimport 'package:flutter_riverpod\u002Fflutter_riverpod.dart';\nimport 'counter.dart';\n\nclass CounterPage extends ConsumerWidget {\n  const CounterPage({super.key});\n\n  @override\n  Widget build(BuildContext context, WidgetRef ref) {\n    final count = ref.watch(counterProvider);\n\n    return Scaffold(\n      appBar: AppBar(title: const Text('Riverpod Counter')),\n      body: Center(\n        child: Text(\n          'Valore: $count',\n          style: Theme.of(context).textTheme.headlineMedium,\n        ),\n      ),\n      floatingActionButton: Row(\n        mainAxisAlignment: MainAxisAlignment.end,\n        children: [\n          FloatingActionButton(\n            onPressed: () => ref.read(counterProvider.notifier).decrement(),\n            child: const Icon(Icons.remove),\n          ),\n          const SizedBox(width: 12),\n          FloatingActionButton(\n            onPressed: () => ref.read(counterProvider.notifier).increment(),\n            child: const Icon(Icons.add),\n          ),\n        ],\n      ),\n    );\n  }\n}","Premendo i pulsanti + e - il valore mostrato a schermo si aggiorna in tempo reale.",{"id":62,"position":63,"title":64,"body":65,"code_snippet":66,"code_language":38,"expected_result":67,"demo_url":10,"video_url":10},109,6,"Gestire stati asincroni con AsyncValue","Riverpod brilla con i dati asincroni. Un provider che restituisce un `Future` espone uno stato di tipo `AsyncValue`, che incapsula i tre casi: caricamento, dato disponibile ed errore.\n\nDefiniamo un provider asincrono che simula una chiamata di rete (ricorda di rigenerare il codice).","import 'package:riverpod_annotation\u002Friverpod_annotation.dart';\n\npart 'user.g.dart';\n\n@riverpod\nFuture\u003CString> userName(UserNameRef ref) async {\n  await Future.delayed(const Duration(seconds: 2));\n  return 'Mario Rossi';\n}","Dopo la rigenerazione è disponibile userNameProvider di tipo FutureProvider.",{"id":69,"position":70,"title":71,"body":72,"code_snippet":73,"code_language":38,"expected_result":74,"demo_url":10,"video_url":10},110,7,"Mostrare caricamento, dato ed errore con .when","Nel widget usiamo `ref.watch` sul provider asincrono e il metodo `.when` di `AsyncValue` per gestire in modo esaustivo tutti gli stati, evitando dimenticanze.","class UserTile extends ConsumerWidget {\n  const UserTile({super.key});\n\n  @override\n  Widget build(BuildContext context, WidgetRef ref) {\n    final userAsync = ref.watch(userNameProvider);\n\n    return userAsync.when(\n      loading: () => const CircularProgressIndicator(),\n      error: (err, stack) => Text('Errore: $err'),\n      data: (name) => Text('Benvenuto, $name!'),\n    );\n  }\n}","Per 2 secondi compare uno spinner, poi appare il messaggio di benvenuto; in caso di eccezione viene mostrato l'errore.",[],1785219611844]