导航到新页面时防止颤动块状态更改
Posted
技术标签:
【中文标题】导航到新页面时防止颤动块状态更改【英文标题】:Prevent flutter bloc state changes when navigate to new page 【发布时间】:2020-11-01 02:30:42 【问题描述】:我是使用 flutter_bloc 的新手,目前在我的项目中遇到问题。
所以,我有这样的 bloc 类:
class TestBloc extends Bloc<TestEvent, TestState>
@override
TestState get initialState => InitialTestState();
@override
Stream<TestState> mapEventToState(
TestEvent event,
) async*
if (event is StateOneEvent)
yield StateOne("one");
else if (event is StateTwoEvent)
yield StateTwo("two");
/// === Event class
abstract class TestEvent extends Equatable
const TestEvent();
class StateOneEvent extends TestEvent
@override
List<Object> get props => [];
class StateTwoEvent extends TestEvent
@override
List<Object> get props => [];
// == State class
abstract class TestState extends Equatable
const TestState();
class InitialTestState extends TestState
@override
List<Object> get props => [];
class StateOne extends TestState
final String value;
StateOne(this.value);
@override
List<Object> get props => [value];
class StateTwo extends TestState
final String value;
StateTwo(this.value);
@override
List<Object> get props => [value];
这是我的主要功能:
void main()
runApp(
MultiBlocProvider(
providers: [
BlocProvider(create: (context)
return TestBloc();
),
],
child: MyApp(),
),
);
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
initialRoute: '/',
routes:
'/': (context) => FirstPage(),
'/second_page': (context) => SecondPage(),
,
);
所以在这里我有两个页面,FirstPage 和 SecondPage 就像这里一样。每个此类都将显示该集团的当前状态。
class FirstPage extends StatefulWidget
@override
_FirstPageState createState() => _FirstPageState();
class _FirstPageState extends State<FirstPage>
@override
void initState()
super.initState();
BlocProvider.of<TestBloc>(context).add(StateOneEvent());
@override
Widget build(BuildContext context)
return Scaffold(body: BlocBuilder<TestBloc, TestState>(
builder: (_, state)
String value = '-';
if (state is StateOne)
value = state.value;
else if (state is StateTwo)
value = state.value;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(value),
RaisedButton(
onPressed: ()
Navigator.pushNamed(context, '/second_page');
,
child: Text('Goto Second Page'),
)
],
),
);
,
));
class SecondPage extends StatefulWidget
@override
_SecondPageState createState() => _SecondPageState();
class _SecondPageState extends State<SecondPage>
@override
void initState()
super.initState();
BlocProvider.of<TestBloc>(context).add(StateTwoEvent());
@override
Widget build(BuildContext context)
return Scaffold(body: BlocBuilder<TestBloc, TestState>(
builder: (_, state)
String value = '-';
if (state is StateOne)
value = state.value;
else if (state is StateTwo)
value = state.value;
return Center(
child: Text(value),
);
,
));
它们都使用相同的 bloc (TestBloc)。在 FirstPage 的初始状态中,我尝试将事件分派给 TestBloc 以将当前状态更改为 StateOne
并在文本中显示当前状态值。所以对于 FirstPage,它将显示 one
。
之后,我尝试导航到与 FirstPage 几乎相同的 SecondPage。在 SecondPage 的初始状态下,我尝试将事件发送到 TestBloc 以将当前状态更改为 StateTwo
,因此它将在文本中显示 two
。
但问题是当我从 SecondPage 导航.pop 或按下返回按钮时,FirstPage 内的文本变为 two
。当我导航到新页面时,似乎 TestBloc 流没有关闭。
我的期望是 FirstPage 应该仍处于显示 one
的最后状态
并且不受我在 SecondPage 中所做的事情的影响。
如何解决这个问题?
谢谢
[更新]
我尝试像这里一样更改 SecondPage,以便它具有另一个 bloc 范围。这实际上解决了问题,但这似乎是正确和好的解决方案?
class SecondPage extends StatefulWidget
@override
_SecondPageState createState() => _SecondPageState();
class _SecondPageState extends State<SecondPage>
TestBloc testBloc = TestBloc();
@override
void initState()
super.initState();
testBloc.add(StateTwoEvent());
@override
Widget build(BuildContext context)
return BlocProvider(
create: (context) => testBloc,
child: Scaffold(body: BlocBuilder<TestBloc, TestState>(
builder: (_, state)
String value = '-';
if (state is StateOne)
value = state.value;
else if (state is StateTwo)
value = state.value;
return Center(
child: Text(value),
);
,
)),
);
【问题讨论】:
尝试提交您的更新作为响应,以便可以看到它。许多读者(包括我自己!)没有阅读整个问题。 【参考方案1】:很难说你到底想达到什么目标。
如果您希望两个页面能够在同一数据上具有不同的状态,则可以为每个页面使用不同的 Bloc 实例。
如果您希望两个页面具有相同的 Bloc 但对状态的反应不同,您可以使用 BlocBuilder
的 buildWhen
方法来控制构建器何时必须重新构建 UI。第一页示例:
BlocBuilder<TestBloc, TestState>(
buildWhen: (prevState, curState)
return curState is StateOne
builder: (_, state)
String value = state.value;
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(value),
RaisedButton(
onPressed: ()
Navigator.pushNamed(context, '/second_page');
,
child: Text('Goto Second Page'),
)
],
),
);
,
但我认为在您的情况下,您希望拥有同一个 Bloc 的单独实例。 buildWhen 主要用于当您只想在需要在 UI 中反映的部分状态更改时重建。
【讨论】:
谢谢你,普埃洛。你已经很有帮助了。但是你也可以分享一下如何实现“distinct Bloc instance”吗? 您需要有两个不同的BlocProviders
为您的页面提供实例,而不是两个都只有一个。【参考方案2】:
您应该创建新的 StateInProgress 那么你的集团应该喜欢
if (event is StateOneEvent)
yield StateInProgress();
//action call
yield StateOne("one");
else if (event is StateTwoEvent)
yield StateInProgress();
//action call
yield StateTwo("two");
【讨论】:
以上是关于导航到新页面时防止颤动块状态更改的主要内容,如果未能解决你的问题,请参考以下文章