Please contact: wechat: Michaelzhoujay for reprint
The original article can be accessedMy blog
This article focuses on the design purpose, usage, and recommended best practices of InheritedWidget
InheritedWidget
The Widget hierarchy of Flutter can be very deep, and transferring data across the Widget hierarchy makes it inefficient and has a lot of bolierplate code.
For example, the following accountId, scopeId, if the MyWidget doesn’t need them, accountId, scopeId will still be the final parameters of the MyWidget because they will accept the parameter value as an argument to the constructor and pass it to MyOtherWidget. It’s very redundant, because MyWidget doesn’t need to know these two parameters at all.
class MyPage extends StatelessWidget {
final int accountId;
final int scopeId;
MyPage(this.accountId, this.scopeId);
Widget build(BuildContext context) {
return newMyWidget(accountId, scopeId); }}class MyWidget extends StatelessWidget {
final int accountId;
final int scopeId;
MyWidget(this.accountId, this.scopeId);
Widget build(BuildContext context) {
// somewhere down the line
newMyOtherWidget(accountId, scopeId); . }}class MyOtherWidget extends StatelessWidget {
final int accountId;
final int scopeId;
MyOtherWidget(this.accountId, this.scopeId);
Widget build(BuildContext context) {
// rinse and repeat.Copy the code
By introducing the InheritedWidget, we can solve this problem.
The idea behind inheritedWidgets is similar to the idea behind Redux. The accountId and scopeId are actually the State of those widgets, where user interactions or other events trigger actions that generate new states. The Widget accepts the new State to generate a new RenderNode to mount to the Widget Tree to complete a rendering.
So how do you get these parameters to pass from one level to another? The answer is to put “State up,” or “State up.
For example, the following code stores accountId and scopeId in the hierarchy described by the InheritedWidget by inserting an InheritedWidget. All hierarchies have access to these two parameters.
class MyInheritedWidget extends InheritedWidget {
final int accountId;
final int scopeId;
MyInheritedWidget(accountId, scopeId, child): super(child);
@override
boolupdateShouldNotify(MyInheritedWidget old) => accountId ! = old.accountId || scopeId ! = old.scopeId; }class MyPage extends StatelessWidget {
final int accountId;
final int scopeId;
MyPage(this.accountId, this.scopeId);
Widget build(BuildContext context) {
return new MyInheritedWidget(
accountId,
scopeId,
constMyWidget(), ); }}class MyWidget extends StatelessWidget {
const MyWidget();
Widget build(BuildContext context) {
// somewhere down the line
constMyOtherWidget(); . }}class MyOtherWidget extends StatelessWidget {
const MyOtherWidget();
Widget build(BuildContext context) {
final myInheritedWidget = MyInheritedWidget.of(context);
print(myInheritedWidget.scopeId);
print(myInheritedWidget.accountId); .Copy the code
Note:
InheritedWidget
thechild
Is a const modifier constructor that allows the child to be cachedaccountId
orscopeId
When the value is updated, the MyInheritedWidget is recreated, but its child may or may not be created, depending on whether it is used or notaccountId
orscopeId
In the example aboveMyOtherWidget
It will be rebuilt, butMyWidget
Not be rebuild- If the tree is rebuilt by another event, such as Orientation Changes,
InheritedWidget
Will be rebuilt, but child doesn’t necessarily get rebuilt either, becauseaccountId
andscopeId
Did not change.
To make the InheritedWidget more efficient, the following best practices are recommended:
Keep inherited widgets small
Keep the semantics of your Context as simple as possible so that Flutter rendering can determine with finer granularity which widgets need to be rebuilt and which need to be reused. Otherwise, you lose the meaning of inheritedWidgets.
To be like this
class TeamContext {
int teamId;
String teamName;
}
class StudentContext {
int studentId;
String studentName;
}
class ClassContext {
intclassId; . }Copy the code
Don’t be so
class MyAppContext {
int teamId;
String teamName;
int studentId;
String studentName;
intclassId; . }Copy the code
Construct child using const
If there is no const, the entire child of the InheritedWidget is not cached, and the selective rebuild of the entire subtree does not take effect.
Manage the Context’s Scope
Because the whole App of Flutter is a Tree, the InheritedWidget can be placed at any level. This is not conducive to the understanding and management of human brain. Therefore, all the scaffolds must be regulated properly. Thus, the maximum granularity of all inheritedWidgets is Page, which is easy for human brain to understand and read.
Do not access context across routes
If you use Navigation. Push a widget, note that the route’s next widget does not inherit the InheritedWidget Context of the previous widget. Instead of pulling the InheriedWidget up, you need to explicitly pass the parameters.