我正在读取 JSON 文件以根据数据生成布局。基本上,它返回一列或一行。我正在使用 FutureBuilder 来处理数据加载。
我还使用ValueNotifier来检测readyToInstall何时发生变化并触发 setState()。
您觉得这个方法怎么样?您认为这是处理这种情况的正确方法吗?
我注意到一件事:当我单击“更新”按钮时,print("ok"); 被调用两次。这是预期的行为吗?
代码运行良好,但我的目标是学习正确的实现方法。
class InitInterface extends StatefulWidget {
const InitInterface({super.key});
@override
State<InitInterface> createState() => _InitInterfaceState();
}
class _InitInterfaceState extends State<InitInterface> {
//used in FutureBuilder to know when we are ready to start install the layout.
late Future<Widget> readyToInstall;
late Stream<Widget> readyToInstall0;
@override
void initState() {
//will read json file and get data to install the layout
readyToInstall = loadLayout();
readyToInstall.then((value){
print('teste');
panelData.addListener(() { //panelData is objhect from a class that extend ValueNotifier
readyToInstall = updateLayout();
setState(() {});
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
FutureBuilder<Widget>(
future: readyToInstall,
builder: (BuildContext context, AsyncSnapshot<Widget> snapshot) {
if (snapshot.hasData) {
print('ok'); //<--called two times after update
return snapshot.data!;
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return const Loading();
}
},
),
ElevatedButton(
onPressed:(){
readyToInstall = updateLayout();
setState(() {});
},
child: Text('Update')),
],
);
}
}
不要
Widget
在您的业务逻辑中使用您应该避免
Widget
在您的 UI 代码之外使用。InitInterfaceState
应该直接接收数据并根据数据决定布局:然后定义一个方法,实际决定是否
Column
应该Row
在小部件树中使用:然后你可以在你的内部调用此函数
FutureBuilder
:避免在
setState
内部使用initState
这里之所以没有问题,是因为它
setState
在回调函数中被调用,这没问题。但这仍然不是一个好的做法,所以你应该考虑将它移动到getLayout
函数中,或者定义一个新的并调用它。我不确定您
ValueNotifier
到底需要什么,所以我无法帮助您。不要在
build
有副作用的方法内编写 UI 逻辑别担心,你没有这样做。它之所以不好,是因为该
build
方法可以连续调用多次。这就是为什么你的方法print("ok")
被多次调用。