Предотвратить изменение состояния c дрожания при переходе на новую страницу - PullRequest
0 голосов
/ 11 июля 2020

Я новичок в использовании flutter_blo c и сейчас сталкиваюсь с проблемой в моем проекте.

Итак, у меня есть класс blo c вроде этого:

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, как здесь. Каждый из этого класса будет показывать текущее состояние blo c.

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

Оба они используют один и тот же blo c (TestBlo c). В исходном состоянии FirstPage я попытался отправить событие TestBlo c, чтобы изменить текущее состояние на StateOne и отобразить текущее значение состояния в тексте. Итак, для FirstPage будет отображаться one.

После этого я попытался перейти на SecondPage, который почти такой же, как FirstPage. В исходном состоянии SecondPage я попытался отправить событие в TestBlo c, чтобы изменить текущее состояние на StateTwo, чтобы затем в тексте отображалось two.

Но проблема в том, когда я перемещаюсь. pop from SecondPage или нажав кнопку «Назад», текст внутри FirstPage станет two. Кажется, что потоки TestBlo c не закрываются, когда я перехожу на новую страницу.

Я ожидаю, что FirstPage должна по-прежнему находиться в своем последнем состоянии, которое отображает one и не зависит от того, что я делаю на SecondPage .

Как решить эту проблему?

Спасибо

[ОБНОВЛЕНИЕ]

Я пытался изменить SecondPage, как здесь, чтобы у него была другая область blo c. На самом деле это решает проблему, но кажется ли это правильным и хорошим решением?

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 голосов
/ 11 июля 2020

Трудно сказать, чего именно вы пытаетесь достичь.

Если вы хотите, чтобы обе страницы могли иметь разные состояния для одних и тех же данных, используя отдельный экземпляр Blo c для каждой страницы это способ go.

Если вы хотите, чтобы обе страницы имели одинаковый Blo c, но по-разному реагировали на состояния, вы можете использовать метод buildWhen из BlocBuilder, чтобы контролировать, когда построитель на самом деле приходится перестраивать пользовательский интерфейс. Пример для 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'),
             )
           ],
        ),
     );
},

Но я думаю, что в вашем случае вы хотите иметь отдельные экземпляры одного и того же Blo c. BuildWhen в основном используется, когда вы хотите перестроить только в случае изменения части состояния, которая должна быть отражена в пользовательском интерфейсе.

...