简体   繁体   English

导航到新页面时防止 flutter bloc state 更改

[英]Prevent flutter bloc state changes when navigate to new page

I'm new in using flutter_bloc and currently facing an issue in my project.我是使用 flutter_bloc 的新手,目前在我的项目中遇到问题。

So, i have bloc class like this:所以,我有这样的块 class :

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];
}

And here is my main function:这是我的主要 function:

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(),
      },
    );
  }
}

So here i have two page, FirstPage and SecondPage like here.所以在这里我有两个页面,FirstPage 和 SecondPage 就像这里一样。 Each of this class will show current state of the bloc.每个 class 都将显示该集团的当前 state。

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),
        );
      },
    ));
  }
}

Both of them use same bloc (TestBloc).他们都使用相同的块(TestBloc)。 In the initial state of FirstPage i tried to dispatch event to TestBloc to change current state to StateOne and display the current state value in a Text.在 FirstPage 的初始 state 中,我尝试将事件分派到 TestBloc 以将当前 state 更改为StateOne并在文本中显示当前 state 值。 So for FirstPage it will show one .所以对于 FirstPage 它将显示one .

After that, i tried to navigate to SecondPage which have almost the same as FirstPage.之后,我尝试导航到与 FirstPage 几乎相同的 SecondPage。 In the inital state of SecondPage i tried to dispatch event to TestBloc to change current state to StateTwo so it will then show two in the Text.在 SecondPage 的初始 state 中,我尝试将事件分派到 TestBloc 以将当前 state 更改为StateTwo ,因此它将在文本中显示two

But the problem is when i navigate.pop from SecondPage or pressing back button, the text inside FirstPage become two .但问题是当我从 SecondPage 导航.pop 或按下后退按钮时,FirstPage 内的文本变为two Seems that TestBloc streams is not closed when i navigate to new page.当我导航到新页面时,似乎 TestBloc 流没有关闭。

My expectation is FirstPage is supposed to still with its last state which is displaying one and not affected by what i do in SecondPage.我的期望是 FirstPage 应该仍然使用它的最后一个 state,它正在显示one并且不受我在 SecondPage 中所做的事情的影响。

How to address this issue?如何解决这个问题?

Thanks谢谢


[UPDATE] [更新]

I tried to changed SecondPage like here so it will have another bloc scope.我尝试像这里一样更改 SecondPage,这样它将有另一个块 scope。 This solves the problem actually, but does this seems to be the right and good solution?这实际上解决了问题,但这似乎是正确和好的解决方案吗?

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),
          );
        },
      )),
    );
  }
}

It is hard to tell what exactly you are trying to achieve.很难说你到底想要达到什么目标。

If you want both pages to be able to have separate states on the same data, using a distinct Bloc instance for each page is the way to go.如果您希望两个页面能够在同一数据上具有不同的状态,则为每个页面使用不同的 Bloc 实例是 go 的方法。

If you want both pages to have the same Bloc but react to states differently you can use the buildWhen method of the BlocBuilder to control when the builder actually has to rebuild the UI.如果您希望两个页面具有相同的 Bloc 但对状态的反应不同,您可以使用BlocBuilderbuildWhen方法来控制构建器何时必须重新构建 UI。 Example for the FirstPage:第一页的例子:

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'),
             )
           ],
        ),
     );
},

But i think in your case you want to have separate instances of the same Bloc.但是我认为在您的情况下,您希望拥有同一个 Bloc 的单独实例。 The buildWhen is mostly used when you only want to rebuild if part of the state changes which needs to be reflected in the UI. buildWhen 主要用于当您只想在 state 的一部分更改需要在 UI 中反映时进行重建。

You should create new StateInProgress then your bloc should like您应该创建新的 StateInProgress 然后您的集团应该喜欢

if (event is StateOneEvent) {
  yield StateInProgress();
  //action call
  yield StateOne("one");
} else if (event is StateTwoEvent) {
  yield StateInProgress();
  //action call
  yield StateTwo("two");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM