qué plugin para diferencia dart flutter

dart - plugin - ¿Cuál es la diferencia entre funciones y clases para crear widgets?



widget plugin (3)

Cuando llame al widget Flutter, asegúrese de utilizar la palabra clave const. Por ejemplo, const MyListWidget();

Me he dado cuenta de que es posible crear widgets utilizando funciones simples en lugar de subclasificar StatelessWidget . Un ejemplo sería este:

Widget function({ String title, VoidCallback callback }) { return GestureDetector( onTap: callback, child: // some widget ); }

Esto es interesante porque requiere mucho menos código que una clase completa. Ejemplo:

class SomeWidget extends StatelessWidget { final VoidCallback callback; final String title; const SomeWidget({Key key, this.callback, this.title}) : super(key: key); @override Widget build(BuildContext context) { return GestureDetector( onTap: callback, child: // some widget ); } }

Así que me he estado preguntando: ¿hay alguna diferencia además de la sintaxis entre las funciones y las clases para crear widgets? ¿Y es una buena práctica usar funciones?


He estado investigando sobre este tema durante los últimos 2 días. Llegué a la siguiente conclusión: está bien dividir partes de la aplicación en funciones. Es ideal que esas funciones devuelvan un StatelessWidget , por lo que se pueden hacer optimizaciones, como hacer que el StatelessWidget const , para que no se reconstruya si no es necesario. Por ejemplo, esta pieza de código es perfectamente válida:

import ''package:flutter/material.dart''; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: ''Flutter Demo'', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: ''Flutter Demo Home Page''), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { ++_counter; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( ''You have pushed the button this many times:'', ), Text( ''$_counter'', style: Theme.of(context).textTheme.display1, ), const MyWidgetClass(key: const Key(''const'')), MyWidgetClass(key: Key(''non-const'')), _buildSomeWidgets(_counter), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: ''Increment'', child: Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); } Widget _buildSomeWidgets(int val) { print(''${DateTime.now()} Rebuild _buildSomeWidgets''); return const MyWidgetClass(key: Key(''function'')); // This is bad, because it would rebuild this every time // return Container( // child: Text("hi"), // ); } } class MyWidgetClass extends StatelessWidget { const MyWidgetClass({Key key}) : super(key: key); @override Widget build(BuildContext context) { print(''${DateTime.now()} Rebuild MyWidgetClass $key''); return Container( child: Text("hi"), ); } }

El uso de la función allí es perfectamente correcto, ya que devuelve un estado const StatelessWidget . Por favor corrígeme si estoy equivocado.


TL; DR: Nunca utilice funciones sobre clases para hacer un árbol de widgets reutilizable . Siempre extraiga estos en un StatelessWidget lugar.

Hay una gran diferencia entre usar funciones en lugar de clases, es decir: el marco no tiene conocimiento de las funciones, pero puede ver las clases.

Considere la siguiente función "widget":

Widget functionWidget({ Widget child}) { return Container(child: child); }

utilizado de esta manera:

functionWidget( child: functionWidget(), );

Y es equivalente a la clase:

class ClassWidget extends StatelessWidget { final Widget child; const ClassWidget({Key key, this.child}) : super(key: key); @override Widget build(BuildContext context) { return Container( child: child, ); } }

utilizado así

new ClassWidget( child: new ClassWidget(), );

En el papel, ambos parecen hacer exactamente lo mismo: crear 2 Container , con uno anidado en el otro. Pero la realidad es ligeramente diferente.

En el caso de las funciones, el árbol de widgets generado se ve así:

Container Container

Mientras que con las clases, el árbol de widgets es:

ClassWidget Container ClassWidget Container

Esto es muy importante porque cambia radicalmente el comportamiento del marco al actualizar un widget. Aquí hay una lista curada de las diferencias:

  1. Clases:

    • permitir la optimización del rendimiento (constructor const, operador == anulación, reconstrucción más granular)
    • tener recarga en caliente
    • se integran en el inspector de widgets (debugFillProperties)
    • puede definir claves
    • puede usar la API de contexto
    • Asegurar que todos los widgets se usen de la misma manera (siempre un constructor)
    • asegúrese de que al cambiar entre dos diseños diferentes se eliminen correctamente los recursos (las funciones pueden reutilizar algún estado anterior)
  2. Funciones:

    • tengo menos código (e incluso allí, hice un generador de código para hacer clases tan pequeñas como funciones: functional_widget )
    • ?

La conclusión ya debería ser bastante clara:

No utilice funciones para crear widgets .