TL; DR
Não use computação pesada dentro do método updateShouldNotify e use const em vez de new ao criar um widget
Em primeiro lugar, devemos entender o que são objetos Widget, Elemento e Render.
- Objetos de renderização são o que realmente é renderizado na tela. Eles são mutáveis , contêm a lógica de pintura e layout. A árvore de renderização é muito semelhante ao Document Object Model (DOM) na web e você pode ver um objeto de renderização como um nó DOM nesta árvore
- Widget - é uma descrição do que deve ser renderizado. Eles são imutáveis e baratos. Portanto, se um widget responde à pergunta "O quê?" (Abordagem declarativa), então um objeto Render responde à pergunta "Como?" (Abordagem imperativa). Uma analogia com a web é um "DOM Virtual".
- Element / BuildContext - é um proxy entre objetos Widget e Render . Ele contém informações sobre a posição de um widget na árvore * e como atualizar o objeto Render quando um widget correspondente é alterado.
Agora estamos prontos para mergulhar no método inheritFromWidgetOfExactType de InheritedWidget e BuildContext .
Como exemplo, recomendo que consideremos este exemplo da documentação do Flutter sobre 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 - apenas um widget que implementa em nosso caso um método importante - updateShouldNotify .
updateShouldNotify - uma função que aceita um parâmetro oldWidget e retorna um valor booleano: verdadeiro ou falso.
Como qualquer widget, InheritedWidget tem um objeto Element correspondente. É InheritedElement . InheritedElement chama updateShouldNotify no widget toda vez que construímos um novo widget (chame setState em um ancestral). Quando updateShouldNotify retorna true, InheritedElement itera por meio de dependências (?) E chama o método didChangeDependencies nele.
Onde InheritedElement obtém dependências ? Aqui devemos olhar para o método inheritFromWidgetOfExactType .
inheritFromWidgetOfExactType - Este método definido em BuildContext e
cada Elemento implementa a interface BuildContext (Element == BuildContext). Portanto, cada elemento tem esse método.
Vamos dar uma olhada no código de inheritFromWidgetOfExactType:
final InheritedElement ancestor = _inheritedWidgets == null ? null : _inheritedWidgets[targetType];
if (ancestor != null) {
assert(ancestor is InheritedElement);
return inheritFromElement(ancestor, aspect: aspect);
}
Aqui, tentamos encontrar um ancestral em _inheritedWidgets mapeado por tipo. Se o ancestral for encontrado, então chamamos de inheritFromElement .
O código para inheritFromElement :
InheritedWidget inheritFromElement(InheritedElement ancestor, { Object aspect }) {
assert(ancestor != null);
_dependencies ??= HashSet<InheritedElement>();
_dependencies.add(ancestor);
ancestor.updateDependencies(this, aspect);
return ancestor.widget;
}
- Adicionamos ancestral como uma dependência do elemento atual (_dependencies.add (ancestor))
- Adicionamos o elemento atual às dependências do ancestral (ancestor.updateDependencies (this, aspect))
- Retornamos o widget do ancestral como resultado de inheritFromWidgetOfExactType (return ancestor.widget)
Portanto, agora sabemos de onde InheritedElement obtém suas dependências.
Agora vamos examinar o método didChangeDependencies . Cada elemento tem este método:
void didChangeDependencies() {
assert(_active); // otherwise markNeedsBuild is a no-op
assert(_debugCheckOwnerBuildTargetExists('didChangeDependencies'));
markNeedsBuild();
}
Como podemos ver este método apenas marca um elemento como sujo e este elemento deve ser reconstruído no próximo quadro. Reconstruir significa construir o método de chamada no elemento de widget correspondente.
Mas e quanto a "Reconstruções de subárvore inteira quando eu reconstruo InheritedWidget?". Aqui devemos lembrar que os Widgets são imutáveis e se você criar um novo widget, o Flutter reconstruirá a subárvore. Como podemos arranjá-lo?
- Widgets de cache manualmente (manualmente)
- Use const porque const cria a única instância de valor / classe