gpt4 book ai didi

dart - InheritedWidget 困惑

转载 作者:IT王子 更新时间:2023-10-29 06:45:35 26 4
gpt4 key购买 nike

flutter documentation for InheritedWidget

Base class for widgets that efficiently propagate information down the tree.

To obtain the nearest instance of a particular type of inherited widget from > a build context, use BuildContext.inheritFromWidgetOfExactType.

Inherited widgets, when referenced in this way, will cause the consumerto rebuild when the inherited widget itself changes state.

鉴于 Flutter 中的小部件是不可变的,并且在示例代码中..

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) => color != old.color;
}

color 属性是 final 所以不能重新分配。假设这个小部件就在树的顶部,就像在大多数示例中一样,它什么时候有用。对于要替换的小部件,必须创建一个新实例。

大概在这样做的地方,也将创建一个作为子传递的任何新实例,导致该子的后代也重建,创建其 childresn 的新实例等。

最终还是重建了整棵树。因此,当 InheritedWidget 实例的数据永远不会为该实例更改时,使用 inheritFromWidgetOfExactType 应用的选择性更新毫无意义?

编辑:

这是我无法理解但可以组合在一起的最简单示例。在此示例中,“更改”应用程序根附近的 InheritedWidget/FrogColor 的唯一方法是重建其父级 (MyApp)。这会导致它重建其子项并创建 FrogColor 的新实例,并向其传递一个新的子实例。我看不到 InheritedWidget/FrogColor 的任何其他方式会像文档中那样改变它的状态

... will cause the consumer to rebuild when the inherited widget itself changes state.

import 'package:flutter/material.dart';
import 'dart:math';

void main() {

runApp(MyApp());
}

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) => color != old.color;
}

class MyApp extends StatefulWidget {
// This widget is the root of your application.

MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp>
{
@override
Widget build(BuildContext context) {
var random = Random(DateTime.now().millisecondsSinceEpoch);

return FrogColor(
color : Color.fromARGB(255,random.nextInt(255),random.nextInt(255),random.nextInt(255)),
child:MaterialApp(
title: 'Flutter Demo',
home: Column (
children: <Widget>[
WidgetA(),
Widget1(),
FlatButton(
child:Text("set state",style:TextStyle(color:Colors.white)),
onPressed:() => this.setState((){})
)
]
)
)
);
}
}

class WidgetA extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Ran Build ${this.runtimeType.toString()}");
return WidgetB();
}
}
class WidgetB extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Ran Build ${this.runtimeType.toString()}");
return Text("SomeText",style:TextStyle(color:FrogColor.of(context).color));
}
}
class Widget1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Ran Build ${this.runtimeType.toString()}");
return Widget2();
}
}
class Widget2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Ran Build ${this.runtimeType.toString()}");
return Text("SomeText",style:TextStyle(color:FrogColor.of(context).color));
}
}

此外,这个的输出是

I/flutter (24881): Ran Build WidgetA
I/flutter (24881): Ran Build WidgetB
I/flutter (24881): Ran Build Widget1
I/flutter (24881): Ran Build Widget2

所以所有的子部件总是被重建。使在 inheritFromWidgetOfExactType 中完成的注册也毫无意义。

编辑2:

回应@RémiRousselet 在评论中的回答,修改上面的例子,类似

class MyAppState extends State<MyApp>
{
Widget child;

MyAppState()
{
child = MaterialApp(
title: 'Flutter Demo',
home: Column (
children: <Widget>[
WidgetA(),
Widget1(),
FlatButton(
child:Text("set state",style:TextStyle(color:Colors.white)),
onPressed:() => this.setState((){})
)
]
)
);
}

@override
Widget build(BuildContext context) {
var random = Random(DateTime.now().millisecondsSinceEpoch);
return FrogColor(
color : Color.fromARGB(255,random.nextInt(255),random.nextInt(255),random.nextInt(255)),
child: child
);
}
}

通过存储不应在构建函数之外修改的树来工作,以便在每次重建时将相同的子树传递给 InhertedWidget。这确实有效,只会导致重建已向 inheritFromWidgetOfExactType 注册的小部件,但不会重建其他小部件。

虽然@RémiRousselet 说将子树存储为状态的一部分是不正确的,但我不认为有任何理由认为这是不对的,事实上他们在一些谷歌教程视频中这样做。 Here她有一个子树作为状态的一部分创建和保存。在她的案例中有 2 个 StatelessColorfulTile() 小部件。

最佳答案

Presumably where this is done, a new instance of whatever is passed as a child will be created too, causing that child's descendants to also rebuild, creating new instances of its children etc..

Ending up with the whole tree rebuilt anyway.

这就是你困惑的来源

小部件重建不会强制其后代重建。

当父级重建时,框架会在内部检查 newChild == oldChild,在这种情况下,子级不会重建。

因此,如果小部件的实例没有改变,或者如果它覆盖operator== 则小部件有可能在其父级更新时不重建。

这也是 AnimatedBuilder 提供 child 属性的原因之一:

AnimatedBuilder(
animation: animation,
builder: (context, child) {
return Container(child: child,);
},
child: Text('Hello world'),
);

这确保了在整个动画持续时间内,child 都得到保留,因此不会重建。带来更加优化的用户界面。

关于dart - InheritedWidget 困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54494398/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com