簡體   English   中英

使用 Flutter_bloc 8.0.0+ 和 Equatable 時如何正確更新我的深層嵌套數據

[英]How To Get My Deeply Nested Data To Update Properly When Using Flutter_bloc 8.0.0+ And Equatable

簡介:我一直在研究這個問題。 該問題涉及使用 Bloc 8.0.0+ 范例更新深度嵌套數據的 state。 我正在使用一個 class ,其中包含深度嵌套的數據(在這個最小的可行代碼中:包含名稱和子項的“集合”旨在成為一個節目系列,並且該系列的子項旨在成為季節,並且很快...)。

嵌套結構是這樣的:

List<CollectionState>
|-- List<CollectionState>
|   |-- List<CollectionState>

代碼的一個重要功能是,將一個子項添加到正確父項的子項列表中,以便在 ListView 中以父項層次結構的正確順序顯示其子項; 即集合有一個系列(8768),該系列有兩個季節(1817 和 7623),當按下一個季節時,一個情節被添加到其正確的父季節,而不是被添加到 ListView 的底部。 在這種情況下,按四次第 1817 季會在其下添加第 2175、2773、5420 和 8826 集,而不是添加到第 7623 季。 在此處輸入圖像描述

問題:據我了解,使用 BLoC 8.0.0+ 時的一個好習慣是使用 Equatable 擴展 CollectionState class。 我提供的以下代碼有效; 但是,它確實使用了這種最佳實踐。 我希望它這樣做,但我遇到了問題,我將很快解釋。 我在 collection_state.dart 的代碼中評論了:

// 1) where Equatable should be extended  

當 CollectionState class 使用 Equatable 擴展時,我在 collection_bloc.dart 中出現問題的代碼中找到了(請注意,問題僅發生在通過擴展 CollectionState ZA2F2ED4F8EBC2CBB4C21A29DC4 來更改代碼時,而 EABDZ4 代碼不使用 EABDZ4) 我在代碼中評論了這條評論:

//TODO: Here is the problem. This code does not work properly when I extend the CollectionState class to Equatable.

令人驚訝的是,在 BLoC 8.0.0+ 中使用深度嵌套數據的在線信息很少。

我是 BLoC 8.0.0+ 的新手,甚至是 Equatable 的新手(到目前為止我一直使用 Provider),我不明白為什么我的代碼在擴展 Equatable 時沒有正確更新。 我想我遇到了一個不變性問題,因為使用AddInfo bloc 事件對 class 的更新被認為與 Equatable 不同。 我不知道如何更改我的代碼以使用 BLoC 深度嵌套數據的最佳實踐。

問題:

  1. 如何更改我的代碼以使用 Equatable 擴展 CollectionState class 並且仍然讓它正確更新我的 UI?

  2. 請記住,我對 Equatable 有一個粗略的了解,我想更多地了解問題的根本根源。 是否 bloc 事件方法沒有產生與 Equatable 足夠不同的 class ,所以它沒有更新或者這里發生了完全不同的事情?

發布規范.yaml

dependencies:
  flutter:
    sdk: flutter

  flutter_bloc: ^8.1.1
  equatable: ^2.0.5

main.dart

import 'package:deeply_nested_objects/add_collection_logic.dart';
import 'package:deeply_nested_objects/bloc/collection_bloc.dart';
import 'package:deeply_nested_objects/bloc/collection_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => CollectionBloc(),
      child: const MaterialApp(
        home: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<CollectionBloc, CollectionState>(
      builder: (context, state) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Deeply nested data and Bloc 8.0.0+'),
          ),
          body: ListView.builder(
            itemCount: state.getAllNodes(state).length,
            itemBuilder: (context, index) {
              var nodes = state.getAllNodes(state)[index];
              return ListTile(
                onTap: () => addToCollection(nodes.showType, index, context),
                leading: Card(
                  child: Text(nodes.name),
                ),
              );
            },
          ),
        );
      },
    );
  }
}

add_collection_logic.dart

import 'dart:math';

import 'package:deeply_nested_objects/bloc/collection_bloc.dart';
import 'package:deeply_nested_objects/bloc/collection_event.dart';
import 'package:deeply_nested_objects/bloc/collection_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

void addToCollection(ShowType showType, int index, BuildContext context) {
    
    if (showType == ShowType.collection) {
      BlocProvider.of<CollectionBloc>(context).add(AddInfo(
        child: CollectionState(
          name: "Series ${(1000 + Random().nextInt(9000))}",
          showType: ShowType.series,
          children: [],
        ),
        index: index,
      ));
    }
    if (showType == ShowType.series) {
      BlocProvider.of<CollectionBloc>(context).add(AddInfo(
        child: CollectionState(
          name: 'Season ${(1000 + Random().nextInt(9000))}',
          showType: ShowType.season,
          children: [],
        ),
        index: index,
      ));
    }
    if (showType == ShowType.season) {
      BlocProvider.of<CollectionBloc>(context).add(AddInfo(
        child: CollectionState(
          name: "Episode ${(1000 + Random().nextInt(9000))}",
          showType: ShowType.episode,
          children: [],
        ),
        index: index,
      ));
    }
  }

collection_event.dart

import 'package:deeply_nested_objects/bloc/collection_state.dart';
import 'package:equatable/equatable.dart';

abstract class CollectionEvents extends Equatable {
  @override
  List<Object> get props => [];
}

class AddInfo extends CollectionEvents {
  AddInfo({required this.index, required this.child});

  final int index;
  final CollectionState child;
}

collection_bloc.dart

import 'package:deeply_nested_objects/bloc/collection_event.dart';
import 'package:deeply_nested_objects/bloc/collection_state.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class CollectionBloc extends Bloc<CollectionEvents, CollectionState> {
  CollectionBloc() : super(CollectionState.initial()) {
    on<AddInfo>((event, emit) {
      if (event.child.showType == ShowType.series) {
        emit(state.copyWith(children: [...state.children, event.child]));
      }
      if (event.child.showType == ShowType.season ||
          event.child.showType == ShowType.episode) {
      //TODO: Here is the problem. This code does not work properly when I extend the CollectionState class to Equatable.
        // get the list of all nodes
        List<CollectionState> list = state.getAllNodes(state);
        // find the parent node while still in the list
        CollectionState parent = list[event.index];
        // add the child to the parent
        parent.children.add(event.child);
        // update the state
        emit(state.copyWith(children: [...state.children]));
      }
    });
  }
}

collection_state.dart

enum ShowType { collection, series, season, episode }

// 1) where should be Equatable
class CollectionState {
  const CollectionState({
    required this.name,
    required this.children,
    required this.showType,
  });
  final String name;
  final List<CollectionState> children;
  final ShowType showType;

  factory CollectionState.initial() {
    return const CollectionState(
      name: "Collection",
      showType: ShowType.collection,
      children: [],
    );
  }

  List<CollectionState> getAllNodes(CollectionState node) {
    // empty list to store the result
    List<CollectionState> result = [];
    // add the current node
    result.add(node);
    // add the children too
    for (CollectionState child in node.children) {
      // composite design pattern seek and find
      result.addAll(getAllNodes(child));
    }
    return result;
  }

  CollectionState copyWith({
    String? name,
    List<CollectionState>? children,
    ShowType? showType,
  }) {
    return CollectionState(
      name: name ?? this.name,
      children: children ?? this.children,
      showType: showType ?? this.showType,
    );
  }
}

您必須在要檢查相等性的 equatable 中分配屬性。

例子:

class SomeClass extends Equatable {
  SomeClass({required this.index});

  final int index;

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

如果我要檢查SomeClass(index: 10) == SomeClass(index: 9)這將是正確的,因為我沒有說它應該在==運算符上尋找什么屬性

如果我將代碼更新為

class SomeClass extends Equatable {
  SomeClass({required this.index});

  final int index;

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

現在相同的檢查將是錯誤的,因為它正在查看索引屬性

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM