TL; DR
N'utilisez pas de calculs lourds dans la méthode updateShouldNotify et utilisez const au lieu de new lors de la création d'un widget
Tout d'abord, nous devons comprendre ce qu'est un objet Widget, Element et Render.
- Les objets de rendu sont ce qui est réellement rendu à l'écran. Ils sont mutables , contiennent la logique de peinture et de mise en page. L'arborescence de rendu est très similaire au modèle d'objet de document (DOM) sur le Web et vous pouvez regarder un objet de rendu comme un nœud DOM dans cette arborescence
- Widget - est une description de ce qui doit être rendu. Ils sont immuables et bon marché. Donc, si un Widget répond à la question "Quoi?" (Approche déclarative), alors un objet Render répond à la question "Comment?" (Approche impérative). Une analogie du Web est un "DOM virtuel".
- Element / BuildContext - est un proxy entre les objets Widget et Render . Il contient des informations sur la position d'un widget dans l'arborescence * et comment mettre à jour l'objet Render lorsqu'un widget correspondant est modifié.
Nous sommes maintenant prêts à plonger dans InheritedWidget et la méthode de BuildContext inheritFromWidgetOfExactType .
À titre d'exemple, je recommande de considérer cet exemple de la documentation de Flutter sur InheritedWidget:
class FrogColor extends InheritedWidget {
const FrogColor({
Key key,
@required this.color,
@required Widget child,
}) : assert(color != null),
assert(child != null),
super(key: key, child: child);
final Color color;
static FrogColor of(BuildContext context) {
return context.inheritFromWidgetOfExactType(FrogColor);
}
@override
bool updateShouldNotify(FrogColor old) {
return color != old.color;
}
}
InheritedWidget - juste un widget qui implémente dans notre cas une méthode importante - updateShouldNotify .
updateShouldNotify - une fonction qui accepte un paramètre oldWidget et renvoie une valeur booléenne: true ou false.
Comme tout widget, InheritedWidget a un objet Element correspondant. Il s'agit de InheritedElement . InheritedElement appelle updateShouldNotify sur le widget chaque fois que nous construisons un nouveau widget (appelez setState sur un ancêtre). Lorsque updateShouldNotify retourne true, InheritedElement itère dans les dépendances (?) Et appelle la méthode didChangeDependencies dessus.
Où InheritedElement obtient les dépendances ? Ici, nous devrions examiner la méthode inheritFromWidgetOfExactType .
inheritFromWidgetOfExactType - Cette méthode définie dans BuildContext et
chaque élément implémente l'interface BuildContext (Element == BuildContext). Donc, chaque élément a cette méthode.
Regardons le code de inheritFromWidgetOfExactType:
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
if (ancestor != null) {
assert(ancestor is InheritedElement);
return inheritFromElement(ancestor, aspect: aspect);
}
Ici, nous essayons de trouver un ancêtre dans _inheritedWidgets mappé par type. Si l'ancêtre est trouvé, nous appelons alors inheritFromElement .
Le code pour inheritFromElement :
InheritedWidget inheritFromElement(InheritedElement ancestor, { Object aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
- Nous ajoutons l'ancêtre en tant que dépendance de l'élément courant (_dependencies.add (ancestor))
- Nous ajoutons l'élément courant aux dépendances de l'ancêtre (ancestor.updateDependencies (this, aspect))
- Nous retournons le widget de l'ancêtre comme résultat de inheritFromWidgetOfExactType (return ancestor.widget)
Nous savons maintenant où InheritedElement obtient ses dépendances.
Regardons maintenant la méthode didChangeDependencies . Chaque élément a cette méthode:
void didChangeDependencies() {
assert(_active); // otherwise markNeedsBuild is a no-op
assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));
markNeedsBuild();
}
Comme nous pouvons le voir, cette méthode marque simplement un élément comme sale et cet élément doit être reconstruit à l'image suivante. Reconstruire signifie appeler la méthode construite sur l'élément de widget correspondant.
Mais qu'en est-il de "La sous-arborescence entière se reconstruit quand je reconstruis InheritedWidget?". Ici, nous devons nous rappeler que les widgets sont immuables et que si vous créez un nouveau widget, Flutter reconstruira le sous-arbre. Comment pouvons-nous y remédier?
- Cachez les widgets à la main (manuellement)
- Utilisez const car const crée la seule instance de valeur / classe