use*_*900 4 dart flutter bloc flutter-bloc
我正在构建一个 tic-tak-toe 应用程序,并决定学习 Flutter 的 BLoC。我的小部件有问题BlocBuilder。
正当我这么想的时候。每次块构建器小部件监听的 Cubit/Bloc 发出新状态时,块构建器都会执行以下例程:
调用buildWhen回调,传递先前的状态作为previous参数,并将新发出的状态作为current参数。
如果buildWhen回调返回 true 则重建。
在重建过程中,调用builder回调函数,传递给定的上下文作为context参数,并将新发出的状态作为state参数。此回调返回我们返回的小部件。
所以结论是current调用的参数buildWhen总是等于调用state的参数builder。但实际上却有所不同:
BlocBuilder<GameCubit, GameState>(
buildWhen: (previous, current) => current is SetSlotSignGameState && (current as SetSlotSignGameState).slotPosition == widget.pos,
builder: (context, state) {
var sign = (state as SetSlotSignGameState).sign;
// Widget creation goes here...
},
);
Run Code Online (Sandbox Code Playgroud)
在builder回调中,它抛出:
构建 BlocBuilder<GameCubit, GameState>(dirty, state: _BlocBuilderBaseState<GameCubit, GameState>#dc100): type 'GameState' is not a subtype of type 'SetSlotSignGameState' in typecast 引发以下 _CastError 相关导致错误的小部件是: BlocBuilder<GameCubit, GameState>
我发出类中状态的方法GameCubit:
// [pos] is the position of the slot clicked
void setSlotSign(Vec2<int> pos) {
// Some code
emit(SetSlotSignGameState(/* Parameter representing the sign that is being placed in the slot*/, pos));
// Some code
emit(TurnChangeGameState());
}
Run Code Online (Sandbox Code Playgroud)
简要介绍一下状态类型。SetSlotSignGameState当用户点击 tic-tac-toe 网格中的插槽并且该插槽为空时发出。所以这个状态意味着我们需要改变某个槽位的符号。TurnChangeGameState当我们需要轮到下一个玩家时发出。
临时解决办法。现在,我通过将回调的状态保存在小部件状态buildWhen的私有字段中,然后从构建器中使用它来修复它。也有这个问题,但我可以将检查从回调移至回调。该解决方案的缺点是非常不优雅且不方便。BlocListenerlistenWhenlisten
buildWhen在初始状态或 Flutter 请求重建时被绕过(甚至不被调用)。
我创建了一个小“测试”来强调:
import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
runApp(BlocTestApp());
}
class BlocTestApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider<TestCubit>(
// Create the TestCubit and call test() event right away
create: (context) => TestCubit()..test(),
child: BlocBuilder<TestCubit, String>(
buildWhen: (previous, current) {
print("Call buildWhen(previous: $previous, current: $current)");
return false;
},
builder: (context, state) {
print("Build $state");
return Text(state);
},
),
),
);
}
}
class TestCubit extends Cubit<String> {
TestCubit() : super("Initial State");
void test() {
Future.delayed(Duration(seconds: 2), () {
emit("Test State");
});
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
I/flutter (13854): Build Initial State
I/flutter (13854): Call buildWhen(previous: Initial State, current: Test State)
Run Code Online (Sandbox Code Playgroud)
从输出中可以看出,初始状态是立即构建的,无需调用buildWhen. 仅当状态发生变化时才buildWhen进行检查。
Flutter Bloc 库的创建者 (@felangel)也在这里概述了这种行为:
这是预期的行为,因为 BlocBuilder 重建有两个原因:
- 集团状态发生变化
- Flutter 将小部件标记为需要重建。
buildWhen 将阻止由 1 触发的构建,但不会阻止由 2 触发的构建。在这种情况下,当语言更改时,整个小部件树可能会被重建,这就是为什么尽管 buildWhen 仍会重建 BlocBuilder。
在您的情况下,根据您透露的少量代码,最好将整个 Tic-Tac-Toe 配置存储在状态中并使用 BLOC 事件来更改它。这样就不需要那个buildWhen条件了。
或者在函数内部进行检查,builder如果逻辑允许您这样做(这是 BLOC 最常用的解决方案)。
回答你的问题(如果到目前为止还不清楚:D):遗憾的是,你不能依赖于过滤发送到function 的buildWhen状态类型builder。
| 归档时间: |
|
| 查看次数: |
3403 次 |
| 最近记录: |