[{"data":1,"prerenderedAt":74},["ShallowReactive",2],{"tutorial-refactoring-del-codice-flutter-con-const-keys-e-widget-separati-per-ottimizzare-le-performance":3,"comments-tutorial-refactoring-del-codice-flutter-con-const-keys-e-widget-separati-per-ottimizzare-le-performance":73},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"video":15,"difficulty":16,"estimated_minutes":17,"flutter_version":18,"status":19,"published_at":20,"meta_title":21,"meta_description":22,"category":23,"author":27,"steps":30},65,"Refactoring del codice Flutter con const, keys e widget separati per ottimizzare le performance","refactoring-del-codice-flutter-con-const-keys-e-widget-separati-per-ottimizzare-le-performance","Impara a rendere le tue app Flutter più veloci e manutenibili applicando const constructor, chiavi corrette e la suddivisione dei widget per ridurre i rebuild inutili.","## Perché ottimizzare i rebuild\n\nUno dei problemi più comuni nelle app Flutter è la ricostruzione (rebuild) eccessiva dei widget, che degrada le performance e rende il codice difficile da mantenere.\n\nIn questo tutorial vedremo tre tecniche pratiche di refactoring che ogni sviluppatore Flutter dovrebbe padroneggiare:\n\n- L'uso di **`const`** per evitare rebuild inutili\n- L'uso corretto delle **`Key`** per preservare lo stato\n- La **separazione dei widget** in classi dedicate\n\nAlla fine avrai una checklist mentale da applicare a ogni tua app per scrivere codice più performante e leggibile.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002F9d18c148-6121-4851-a8a7-966fff186f36.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1784397378839-57f82daee0c3?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3ODczMjczMTN8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Julia Taubitz","https:\u002F\u002Funsplash.com\u002F@justmejuliee","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fstacked-wooden-blocks-forming-an-unstable-wall-structure-7C-PbdzUFmE",null,"intermediate",35,"3.x","published","2026-08-16T04:30:56+00:00","Ottimizzare i rebuild in Flutter: const, key e widget","Guida pratica per ottimizzare le performance Flutter riducendo i rebuild con const constructor, Key e separazione dei widget in classi dedicate.",{"id":24,"name":25,"slug":26},3,"Best practice","best-practice",{"id":28,"name":29},1,"Flutter Bot",[31,38,45,52,59,66],{"id":32,"position":28,"title":33,"body":34,"code_snippet":35,"code_language":36,"expected_result":37,"demo_url":15,"video_url":15},433,"Individuare i rebuild con il DevTools e debugPrint","Prima di ottimizzare, dobbiamo **misurare**. Il modo più semplice per capire quante volte un widget viene ricostruito è stampare un messaggio nel metodo `build`.\n\nApri anche il **Flutter DevTools** (`Performance` e `Widget rebuild stats`) per avere una visione grafica dei rebuild. Attiva la voce *Track Widget Rebuilds* dal menu Performance.\n\nCreiamo una piccola app di esempio con un contatore e un widget \"costoso\" che vogliamo monitorare.","class CounterPage extends StatefulWidget {\n  const CounterPage({super.key});\n\n  @override\n  State\u003CCounterPage> createState() => _CounterPageState();\n}\n\nclass _CounterPageState extends State\u003CCounterPage> {\n  int _count = 0;\n\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('build CounterPage');\n    return Scaffold(\n      appBar: AppBar(title: const Text('Rebuild demo')),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: [\n            _ExpensiveHeader(),\n            Text('Conteggio: $_count'),\n          ],\n        ),\n      ),\n      floatingActionButton: FloatingActionButton(\n        onPressed: () => setState(() => _count++),\n        child: const Icon(Icons.add),\n      ),\n    );\n  }\n}\n\nclass _ExpensiveHeader extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('build _ExpensiveHeader');\n    return const Padding(\n      padding: EdgeInsets.all(16),\n      child: Text('Header statico', style: TextStyle(fontSize: 24)),\n    );\n  }\n}","dart","Nella console vedrai 'build _ExpensiveHeader' stampato a ogni tap sul FAB, anche se il suo contenuto non cambia mai.",{"id":39,"position":40,"title":41,"body":42,"code_snippet":43,"code_language":36,"expected_result":44,"demo_url":15,"video_url":15},434,2,"Applicare const per bloccare i rebuild inutili","Il modo più immediato per evitare che un widget venga ricostruito è renderlo **`const`**. Un widget `const` viene istanziato una sola volta e Flutter lo riconosce come identico a quello precedente, saltando la ricostruzione.\n\nAffinché un widget possa essere `const`, il suo costruttore deve essere `const` e tutti i suoi parametri devono essere valori costanti a compile-time.\n\nNel nostro esempio, `_ExpensiveHeader` non ha stato né parametri variabili: aggiungiamo un costruttore `const` e usiamolo come `const _ExpensiveHeader()`.","class _ExpensiveHeader extends StatelessWidget {\n  const _ExpensiveHeader();\n\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('build _ExpensiveHeader');\n    return const Padding(\n      padding: EdgeInsets.all(16),\n      child: Text('Header statico', style: TextStyle(fontSize: 24)),\n    );\n  }\n}\n\n\u002F\u002F Nel build della pagina:\n\u002F\u002F children: [\n\u002F\u002F   const _ExpensiveHeader(),\n\u002F\u002F   Text('Conteggio: $_count'),\n\u002F\u002F ],","Ora 'build _ExpensiveHeader' viene stampato una sola volta all'avvio: i tap successivi sul FAB non lo ricostruiscono più.",{"id":46,"position":24,"title":47,"body":48,"code_snippet":49,"code_language":50,"expected_result":51,"demo_url":15,"video_url":15},435,"Attivare il linter per suggerire le const automaticamente","Aggiungere manualmente `const` ovunque è tedioso. Fortunatamente esistono regole di lint che segnalano dove è possibile inserirlo.\n\nApri (o crea) il file `analysis_options.yaml` nella root del progetto e attiva le regole `prefer_const_constructors`, `prefer_const_literals_to_create_immutables` e `prefer_const_constructors_in_immutables`.\n\nL'IDE mostrerà un avviso e potrai applicare la fix automatica con `dart fix --apply`.","include: package:flutter_lints\u002Fflutter.yaml\n\nlinter:\n  rules:\n    prefer_const_constructors: true\n    prefer_const_literals_to_create_immutables: true\n    prefer_const_constructors_in_immutables: true\n    prefer_const_declarations: true","yaml","Eseguendo 'dart fix --apply' da terminale, il framework aggiunge automaticamente i const mancanti in tutto il progetto.",{"id":53,"position":54,"title":55,"body":56,"code_snippet":57,"code_language":36,"expected_result":58,"demo_url":15,"video_url":15},436,4,"Separare i widget in classi invece di usare metodi helper","Un anti-pattern comune è estrarre parti di UI in **metodi helper** (es. `Widget _buildHeader()`). Questi metodi NON creano un nuovo elemento nell'albero: vengono rieseguiti ogni volta che il widget genitore fa il build.\n\nLa best practice è estrarre l'UI in **classi widget dedicate**. In questo modo Flutter può ottimizzare i rebuild in modo indipendente e, se il widget è `const`, evitarli del tutto.\n\nConfrontiamo i due approcci.","\u002F\u002F ❌ ANTI-PATTERN: metodo helper, si ricostruisce sempre\nWidget _buildFooter() {\n  debugPrint('build footer helper');\n  return const Text('Footer');\n}\n\n\u002F\u002F ✅ PREFERIBILE: classe widget separata e const\nclass _Footer extends StatelessWidget {\n  const _Footer();\n\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('build _Footer');\n    return const Text('Footer');\n  }\n}\n\n\u002F\u002F Uso nel build:\n\u002F\u002F const _Footer(),  \u002F\u002F \u003C-- non si ricostruisce","Il metodo helper stampa il log a ogni rebuild del genitore, mentre il widget in classe const viene costruito una sola volta.",{"id":60,"position":61,"title":62,"body":63,"code_snippet":64,"code_language":36,"expected_result":65,"demo_url":15,"video_url":15},437,5,"Usare le Key per preservare lo stato negli elenchi dinamici","Quando riordini, inserisci o rimuovi elementi con stato da una lista, Flutter potrebbe associare lo stato all'elemento sbagliato perché confronta i widget per posizione e tipo.\n\nLe **`Key`** (in particolare `ValueKey` e `ObjectKey`) permettono a Flutter di identificare univocamente ogni widget, preservando correttamente lo stato durante le modifiche alla lista.\n\nVediamo un elenco di card con stato che, senza key, perde il colore corretto quando riordiniamo gli elementi.","class ColorTile extends StatefulWidget {\n  final String id;\n  final String label;\n\n  const ColorTile({required this.id, required this.label})\n      : super(key: const ValueKey('placeholder'));\n\n  \u002F\u002F Meglio passare la key dall'esterno:\n  \u002F\u002F ColorTile({required this.id, required this.label}) : super(key: ValueKey(id));\n\n  @override\n  State\u003CColorTile> createState() => _ColorTileState();\n}\n\nclass _ColorTileState extends State\u003CColorTile> {\n  Color _color = Colors.grey;\n\n  @override\n  Widget build(BuildContext context) {\n    return ListTile(\n      tileColor: _color,\n      title: Text(widget.label),\n      onTap: () => setState(() => _color = Colors.amber),\n    );\n  }\n}\n\n\u002F\u002F Nella costruzione della lista, assegna sempre una key stabile:\n\u002F\u002F children: items.map((e) => ColorTile(key: ValueKey(e.id), id: e.id, label: e.label)).toList(),","Con le ValueKey basate su un id stabile, dopo aver riordinato la lista ogni tile mantiene il proprio stato (colore) corretto.",{"id":67,"position":68,"title":69,"body":70,"code_snippet":71,"code_language":36,"expected_result":72,"demo_url":15,"video_url":15},438,6,"Isolare i rebuild con RepaintBoundary e ValueListenableBuilder","Come tocco finale, isoliamo le porzioni di UI che cambiano frequentemente in modo da non ricostruire tutto l'albero.\n\n- **`ValueListenableBuilder`** ricostruisce solo il widget che dipende da un valore, lasciando invariato il resto.\n- **`RepaintBoundary`** crea un layer separato per la pittura, evitando che un ridisegno frequente costringa a ridipingere anche i widget vicini.\n\nRifattorizziamo il contatore per aggiornare solo il testo, non l'intera pagina.","class CounterPage extends StatelessWidget {\n  CounterPage({super.key});\n\n  final ValueNotifier\u003Cint> _count = ValueNotifier(0);\n\n  @override\n  Widget build(BuildContext context) {\n    debugPrint('build CounterPage'); \u002F\u002F ora eseguito una sola volta\n    return Scaffold(\n      appBar: AppBar(title: const Text('Rebuild ottimizzato')),\n      body: Center(\n        child: Column(\n          mainAxisAlignment: MainAxisAlignment.center,\n          children: [\n            const _ExpensiveHeader(),\n            RepaintBoundary(\n              child: ValueListenableBuilder\u003Cint>(\n                valueListenable: _count,\n                builder: (context, value, _) => Text('Conteggio: $value'),\n              ),\n            ),\n          ],\n        ),\n      ),\n      floatingActionButton: FloatingActionButton(\n        onPressed: () => _count.value++,\n        child: const Icon(Icons.add),\n      ),\n    );\n  }\n}","Toccando il FAB si ricostruisce solo il Text del conteggio: 'build CounterPage' non viene più stampato, dimostrando l'isolamento del rebuild.",[],1789120601636]