颤振:BLoC Builder 未更新,尽管我在调试器中看到新的/不同的状态

Posted

技术标签:

【中文标题】颤振:BLoC Builder 未更新,尽管我在调试器中看到新的/不同的状态【英文标题】:flutter: BLoC Builder not updating, though I see new/different state in debugger 【发布时间】:2021-01-05 15:05:23 【问题描述】:

我今天的第二个奇怪事件。当我在 bloc.dart(库,而不是我的文件)中跟踪调试器时,我看到 transition.nextState == state && _emittedfalse,它不会更新我的小部件(nextState 的列表大小为 2,状态为 10 - _emitted 为真) .据我了解,构建器应该没问题,还有其他地方可以查看它为什么不更新吗?

在我展示代码之前先解释一下逻辑

    我在应用启动时获取我的数据

    BlocProvider(create: (context) =>
      LogicGraphsPStmntBloc(logicGraphsRepository:
      logicGraphsRepository)..add(LogicGraphsNextProblemRequested()),
    

    这会返回一个包含 10 个字符串的列表,我将其存储在我的 _bloc.dart 文件中(不确定这是否是最先进的)

    这 10 个字符串通过状态 LogicGraphsPStmntLoadSuccess(statements) 发送并正确呈现为按钮

    如果我单击一个按钮,则只会显示第一个和选定的字符串。使用onPressed: () BlocProvider.of<LogicGraphsPStmntBloc>(context).add(LogicGraphsPStmntCollapsed(statement: index-1));, 正确触发事件

    这会正确触发状态yield LogicGraphsPStmntLoadSuccess(statementsShown);,现在列表中只有 2 个元素(与第 3 步中的 10 个元素相比),但不会导致重新渲染

    如果我使用调试器进入状态,我可以看到两个状态具有不同数量的元素。

我的状态

abstract class LogicGraphsPStmntState extends Equatable 
  const LogicGraphsPStmntState();
  @override
  List<Object> get props => [];


class LogicGraphsPStmntLoadSuccess extends LogicGraphsPStmntState 
  const LogicGraphsPStmntLoadSuccess([this.statements = const []]);
  final List<String> statements;

  @override
  List<Object> get props => [];

  @override
  String toString() => 'LogicGraphsPStmntLoadSuccess  statements: $statements ';

我的块(不完全是,因为我的子函数中释放状态的代码没有达到my other issue 中描述的那样。所以目前我在 mapEventToState= 中将这些子函数行作为意大利面条=

class LogicGraphsPStmntBloc extends Bloc<LogicGraphsPStmntEvent, LogicGraphsPStmntState> 
  LogicGraphsPStmntBloc(@required this.logicGraphsRepository) : super(LogicGraphsPStmntInProgress());
  final LogicGraphsRepository logicGraphsRepository;
  List<String> statements;
  int currentProblem = -1;

  @override
  Stream<LogicGraphsPStmntState> mapEventToState(LogicGraphsPStmntEvent event) async* 
        if (event is LogicGraphsNextProblemRequested) 
          _mapLGPStmntNewProblemRequested();
          _mapLGPStmntLoadRequested(currentProblem);
        
        else if (event is LogicGraphsPStmntLoadRequested) 
          _mapLGPStmntLoadRequested(currentProblem);
        
        else if (event is LogicGraphsPStmntCollapsed) 
          _mapLGPStmntCollapseRequested(event);
  
  Stream<LogicGraphsPStmntState> _mapLGPStmntNewProblemRequested() async* 
        try 
          currentProblem =
          await getNextProblem(currentProblem == null ? -1 : currentProblem);
          statements =
          await logicGraphsRepository.getProblemStmntList(currentProblem);
          _mapLGPStmntLoadRequested(currentProblem);
         catch (_) 
          yield LogicGraphsPStmntLoadFailure();
        
  
  Stream<LogicGraphsPStmntState> _mapLGPStmntLoadRequested(int problem) async* 
          try 
            yield LogicGraphsPStmntLoadSuccess(statements);
           catch (_) 
            yield LogicGraphsPStmntLoadFailure();
          
  
  Stream<LogicGraphsPStmntState> _mapLGPStmntCollapseRequested(
          LogicGraphsPStmntCollapsed event) async* 
          List<String> statementsShown = [];
          statementFocussed = event.statement;
          statementsShown.add(statements[0]);
          statementsShown.add(statements[statementFocussed]);
          yield LogicGraphsPStmntLoadSuccess(statementsShown);
  

我的小部件

class LogicGraphpage extends StatelessWidget 
  final LogicGraphsRepository logicGraphsRepository = LogicGraphsRepository(
      logicGraphsApiClient: LogicGraphsApiClient());

  @override
  Widget build(BuildContext context) 
    return CupertinoPageScaffold(
      child: BlocProvider(
        create: (context) =>
        LogicGraphsPStmntBloc(logicGraphsRepository: logicGraphsRepository)
          ..add(LogicGraphsNextProblemRequested()),
          child:BlocBuilder<LogicGraphsPStmntBloc, LogicGraphsPStmntState>(
            builder: (context, state) 
              if (state is LogicGraphsPStmntLoadSuccess) 
                final List<String> statements = state.statements;
                return ListView.builder(
                    itemCount: statements.length,
                    itemBuilder: (BuildContext context, int index) 
                      return CupertinoButton(
                        padding: EdgeInsets.all(0),
                        child: Text(statements[index])
                        onPressed: () BlocProvider.of<LogicGraphsPStmntBloc>(context).add(LogicGraphsPStmntCollapsed(statement: index-1));,
                      );
                    );
              
              else return Container();
            
        )
      ),
    );
  

bloc.dart 库中的函数,我假设新状态已发出。您会看到if (transition.nextState == state &amp;&amp; _emitted) return; 行。下一个状态有 2 个元素,状态有 10 个,_emitted 为真,所以我假设代码继续。而是触发返回并跳过带有emit(transition.nextState); 的行。

任何帮助都非常感谢,因为这是我第一次使用 BLoC/equatable 和 Flutter 的经验,总的来说对我来说还是很新的。但我正在进步!

 void _bindEventsToStates() 
    _transitionSubscription = transformTransitions(
      transformEvents(
        _eventController.stream,
            (event) => mapEventToState(event).map(
              (nextState) => Transition(
            currentState: state,
            event: event,
            nextState: nextState,
          ),
        ),
      ),
    ).listen(
          (transition) 
        if (transition.nextState == state && _emitted) return; // <<<<<<<<<<<
        try 
          onTransition(transition);
          emit(transition.nextState);
         on dynamic catch (error, stackTrace) 
          onError(error, stackTrace);
        
        _emitted = true;
      ,
      onError: onError,
    );
  

【问题讨论】:

【参考方案1】:

我猜集团无法区分LogicGraphsPStmntLoadSuccess(statements)LogicGraphsPStmntLoadSuccess(statementsShown),因为它们是相同的状态,我认为它无法发现不同参数之间的差异。

所以我建议这样做: 在产生LogicGraphsPStmntLoadSuccess(statementsShown) 之前尝试产生一个“切换”状态,就像我之前不知道LogicGraphsPStmntChangeStatement 一样。 所以:

yield LogicGraphsPStmntChangeStatement;
yield LogicGraphsPStmntLoadSuccess(statementsShown);

这应该可以解决问题。

【讨论】:

你完全正确!所以状态变化意味着状态的变化,而不是状态的变化。因此,当我对此进行调试时, nextstate == state 不会比较值,而是比较状态的“类型”。是什么让我想知道:如果我在线获取数据并在 2 秒后返回一个块,在 10 秒后返回一些块,loadSuccess 状态会等待 10 秒并显示所有数据,它会在 2 秒后提供第一个块,其余的稍后提供还是停止交付2s 后(不确定这种传输中是否存在某种 EOF)? 感谢您提供此解决方案,但还有其他方法吗?我的意思是有没有办法让 bloc 知道状态已经改变,因为状态内的数据发生了变化? 是的,有办法,看看这篇文章:medium.com/flutterworld/…

以上是关于颤振:BLoC Builder 未更新,尽管我在调试器中看到新的/不同的状态的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Bloc - Flutter Bloc 状态未更新

BLoC 产生新状态后 BlocBuilder() 未更新

无法使用颤振 Bloc 模式更新小部件外部的 UI

在有状态小部件外部调用方法以使用颤振 Bloc 更新 UI

BLoC 的事件映射器未执行,尽管调试表明它应该 8-/

尝试从 youtube-search-tutorial 实现 BLoC 时出现颤振错误