一旦使用 bloc 触发事件,底页就会重复显示

Posted

技术标签:

【中文标题】一旦使用 bloc 触发事件,底页就会重复显示【英文标题】:bottom sheet is showing repeatedly once event triggred using bloc 【发布时间】:2021-11-12 09:28:17 【问题描述】:

我是一个新手,正在学习如何使用冻结的 bloc。当用户单击浮动操作按钮时,我创建了一个底部工作表,底部工作表出现。当我单击以选择一个收音机时,底部表包含文本字段和三个单选组,底部表再次像此 GIF 一样弹出。 https://drive.google.com/file/d/1iU06adGcwjEaw9z2LsmO5xS24CC6OQfT/view?usp=sharing

集团是:

class NoteBloc extends Bloc<NoteEvent, NoteState> 
  NoteBloc() : super(NoteState.initial());

  @override
  Stream<NoteState> mapEventToState(
    NoteEvent event,
  ) async* 
    yield* event.map(
      addNewNoteButtonEvent: (AddNewNoteButtonEvent e) async* 
          yield state.copyWith(
            isAddNewNoteButtonClickedState: e.isClickedEvent,
          );
      ,
      radioEvent: (RadioEvent e) async* 
        yield state.copyWith(radioGroupState: e.value);
      ,
      textInputEvent: (TextInputEvent e) async* 
        yield state.copyWith(textInputState: Note(value: e.value));
      ,
    );
  

事件是:

class NoteEvent with _$NoteEvent 
  const factory NoteEvent.addNewNoteButtonEvent(
      required bool isClickedEvent) = AddNewNoteButtonEvent;
  const factory NoteEvent.radioEvent(required int value) = RadioEvent;
  const factory NoteEvent.textInputEvent(required String value) =
      TextInputEvent;

状态是:

class NoteState with _$NoteState 
  const factory NoteState(
    // required bool showSaveIconState,
    required int radioGroupState,
    required bool isAddNewNoteButtonClickedState,
    required Note textInputState,
  ) = _NoteState;
  // initialize every state
  factory NoteState.initial() => NoteState(
        radioGroupState: 1,
        isAddNewNoteButtonClickedState: false,
        textInputState: Note(value: ''),
      );

首页代码为:

class HomePage extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
    return BlocConsumer<NoteBloc, NoteState>(
      listener: (context, state) 
        // if (state is AddNoteClickedState) 
        if (state.isAddNewNoteButtonClickedState) 
          
          // show navigator
          _scaffoldKey.currentState!
              .showBottomSheet((context) => const AddNewNoteBottomSheet())
              .closed
              .then(
            (value) 
              // Change state
              // to tell the bloc that
              // the bottom sheet is closed
              context.read<NoteBloc>().add(
                    const NoteEvent.addNewNoteButtonEvent(
                      isClickedEvent: false, // !state.isAddNewNoteClickedState,
                    ),
                  );
            ,
          );
        
      ,
      builder: (context, state) 
        return DefaultTabController(
          length: 3,
          child: Scaffold(
            key: _scaffoldKey,
            // add note float action button
            floatingActionButton: InkWell(
              onTap: () 
                // make button clicked
                // to open the bottom sheet
                context.read<NoteBloc>().add(
                      const NoteEvent.addNewNoteButtonEvent(
                        isClickedEvent: true, //!state.isAddNewNoteClickedState,
                      ),
                    );
                // print(state);
              ,
              // for float action button
              // icon shape
              child: Container(
                clipBehavior: Clip.antiAliasWithSaveLayer,
                height: 11.h,
                width: 10.h,
                decoration: BoxDecoration(
                  shape: BoxShape.rectangle,
                  borderRadius: BorderRadius.all(Radius.circular(1.w)),
                  color: const Color(accentColor),
                ),
                // add note icon
                child: Icon(
                  state.isAddNewNoteButtonClickedState ? Icons.save : Icons.add,
                  color: const Color(whiteColor),
                  size: 9.h,
                ),
              ),
        );
      ,
    );
  

AddNewNoteBottomSheet 代码为:

// For adding new note
class AddNewNoteBottomSheet extends StatelessWidget 
  const AddNewNoteBottomSheet();

  @override
  Widget build(BuildContext context) 
    TextEditingController _textEditingController = TextEditingController();
    return Container(
      // Contains all
      // bottom sheet components
      child: Column(
              children: [
          // bottom sheet body
          Expanded(
            child: SingleChildScrollView(
              child: BlocBuilder<NoteBloc, NoteState>(
                builder: (context, state) 
                  // print("Helllo $state.maybeMap(orElse: (),radioClickState: (stat)=>stat.value)");
                  return Column(
                    children: [
                      
                      // Today Radio
                      ListTile(
                        title: Text(
                          AppLocalizations.of(context)!.homeTodayTapTitle,
                          style: Theme.of(context)
                              .tabBarTheme
                              .unselectedLabelStyle,
                        ),
                        contentPadding: const EdgeInsets.all(0),
                        autofocus: true,
                        leading: Radio<int>(
                          value: 1,
                          //get group value
                          groupValue: state.radioGroupState,
                          onChanged: (value) 
                            // tell bloc i click you
                            context
                                .read<NoteBloc>()
                                .add(NoteEvent.radioEvent(value: value!));
                          ,
                        ),
                      ),
                      // Tomorrow Radio
                      ListTile(
                        contentPadding: const EdgeInsets.all(0),
                        title: Text(
                          AppLocalizations.of(context)!.homeTomorrowTapTitle,
                          style: Theme.of(context)
                              .tabBarTheme
                              .unselectedLabelStyle,
                        ),
                        leading: Radio<int>(
                          value: 2,
                          //get group value
                          groupValue: state.radioGroupState,
                          onChanged: (value) 
                            // tell bloc i click you
                            context.read<NoteBloc>().add(
                                  NoteEvent.radioEvent(value: value!),
                                );
                          ,
                        ),
                      ),
                      // Some Day Radio
                      ListTile(
                        contentPadding: const EdgeInsets.all(0),
                        title: Text(
                          AppLocalizations.of(context)!.homeSomeDayTapTitle,
                          style: Theme.of(context)
                              .tabBarTheme
                              .unselectedLabelStyle,
                        ),
                        leading: Radio<int>(
                          value: 3,
                          //get group value
                          groupValue: state.radioGroupState,

                          onChanged: (value) 
                            // tell bloc i click you
                            context.read<NoteBloc>().add(
                                  NoteEvent.radioEvent(value: value!),
                                );
                          ,
                        ),
                      ),
                    ],
                  );
                ,
              ),
            ),
          ),
        ],
      ),
    );
  

【问题讨论】:

【参考方案1】:

问题定义:出现此问题是因为您在 bloc 上使用了 state.copyWith。当您使用 copyWith 时,即使您不更新 isAddNewNoteButtonClickedState 变量,如果您不更改它,您的状态也会保留该值(设置后保持为真,如果不更改则永远不会更改)。因为在 copyWith 方法上,更新逻辑的工作方式类似于;

YourState copyWith(bool isAddNewNoteButtonClickedState) 
   return YourState(isAddNewNoteButtonClickedState: isAddNewNoteButtonClickedState ?? this. isAddNewNoteButtonClickedState,)

当您产生另一个状态时,isAddNewNoteButtonClickedState 保持为真,并且您的侦听器显示另一个模式,因为您的 isAddNewNoteButtonClickedState 没有改变。

解决方案:您可以通过(将isAddNewNoteButtonClickedState: false添加到其他状态)来解决此问题:

    class NoteBloc extends Bloc<NoteEvent, NoteState> 
  NoteBloc() : super(NoteState.initial());

  @override
  Stream<NoteState> mapEventToState(
    NoteEvent event,
  ) async* 
    yield* event.map(
      addNewNoteButtonEvent: (AddNewNoteButtonEvent e) async* 
          yield state.copyWith(
            isAddNewNoteButtonClickedState: e.isClickedEvent,
          );
      ,
      radioEvent: (RadioEvent e) async* 
        yield state.copyWith(radioGroupState: e.value, isAddNewNoteButtonClickedState: false);
      ,
      textInputEvent: (TextInputEvent e) async* 
        yield state.copyWith(textInputState: Note(value: e.value), isAddNewNoteButtonClickedState: false);
      ,
    );
  

补充说明: 由于您不是在整体中转换事件或做一些琐碎的事情,因此您可以使用 cubit 来简化您的状态管理和业务逻辑。

【讨论】:

以上是关于一旦使用 bloc 触发事件,底页就会重复显示的主要内容,如果未能解决你的问题,请参考以下文章

Google Maps API 标记点击事件未触发 [重复]

jquery 事件,注册 与重复事件处理

Flutter - 了解 Provider、Bloc 的生命周期以及何时处理流 [重复]

jQuery - 找出触发事件的原因[重复]

Flutter 再次触发 bloc 事件

024-母版页