J'ai réalisé qu'il est possible de créer des widgets en utilisant des fonctions simples au lieu de sous-classer StatelessWidget . Un exemple serait ceci:
Widget function({ String title, VoidCallback callback }) {
return GestureDetector(
onTap: callback,
child: // some widget
);
}
Ceci est intéressant car il nécessite loin moins de code qu'une classe complète. Exemple:
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
);
}
}
Je me suis donc demandé: en dehors de la syntaxe, existe-t-il une différence entre les fonctions et les classes pour créer des widgets? Et est-ce une bonne pratique d’utiliser des fonctions?
TL; DR: N'utilisez jamais de fonctions sur des classes pour créer un widget-tree réutilisable . Extrayez-les toujours dans un StatelessWidget .
Il y a une différence énorme entre utiliser des fonctions plutôt que des classes, c'est-à-dire que: le framework ignore les fonctions, mais peut voir les classes.
Considérez la fonction "widget" suivante:
Widget functionWidget({ Widget child}) {
return Container(child: child);
}
utilisé de cette façon:
functionWidget(
child: functionWidget(),
);
Et c'est l'équivalent de classe:
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,
);
}
}
utilisé comme ça:
new ClassWidget(
child: new ClassWidget(),
);
Sur le papier, les deux semblent faire exactement la même chose: créez 2 Container
, l'un imbriqué dans l'autre. Mais la réalité est légèrement différente.
Dans le cas de fonctions, l’arborescence des widgets générés se présente comme suit:
Container
Container
Alors qu'avec des classes, l'arborescence des widgets est:
ClassWidget
Container
ClassWidget
Container
Ceci est très car il modifie radicalement le comportement du framework lors de la mise à jour d'un widget. Voici une liste organisée des différences:
Des classes:
Les fonctions:
La conclusion devrait être assez claire déjà:
N'utilisez pas de fonctions pour créer des widgets .
Je fais des recherches sur cette question depuis 2 jours. Je suis arrivé à la conclusion suivante: il est normal de décomposer des éléments de l'application en fonctions. Il est tout simplement idéal que ces fonctions renvoient un StatelessWidget
. Vous pouvez donc effectuer des optimisations, telles que rendre le StatelessWidget
const
, afin qu'il ne soit pas reconstruit s'il ne le doit pas. Par exemple, ce morceau de code est parfaitement valide:
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"),
);
}
}
L'utilisation de function y est parfaitement correcte, car elle renvoie un const StatelessWidget
. Corrigez-moi si j'ai tort, s'il-vous plait.