导航到新页面时,防止抖动状态更改

时间:2020-07-11 13:20:11

标签: flutter bloc flutter-bloc

我是使用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),
        );
      },
    ));
  }
}

它们两个都使用相同的块(TestBloc)。在FirstPage的初始状态下,我尝试将事件调度到TestBloc,以将当前状态更改为StateOne,并在Text中显示当前状态值。因此,对于FirstPage,它将显示one

在那之后,我尝试导航到与FirstPage几乎相同的SecondPage。在SecondPage的初始状态下,我尝试将事件调度到TestBloc,以将当前状态更改为StateTwo,这样它将在文本中显示two

但是问题是当我从SecondPage导航或按返回按钮时,FirstPage内的文本变为two。导航到新页面时,似乎TestBloc流没有关闭。

我的期望是FirstPage应该仍处于显示one的最后状态 不受我在SecondPage中的操作的影响。

如何解决此问题?

谢谢


[UPDATE]

我试图像这里一样更改SecondPage,以便它具有另一个块范围。这实际上可以解决问题,但这似乎是正确且好的解决方案吗?

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 个答案:

答案 0 :(得分:0)

很难说出您到底想达到什么目标。

如果您希望两个页面在同一数据上都可以具有单独的状态,则可以为每个页面使用不同的Bloc实例。

如果您希望两个页面具有相同的Bloc但对状态的反应不同,则可以使用buildWhen的{​​{1}}方法来控制构建器实际上何时必须重建UI。 FirstPage示例:

BlocBuilder

但是我想在您的情况下,您希望拥有同一Bloc的单独实例。当仅在部分状态更改需要重建时才需要重建时才需要使用buildWhen。