在 Flutter 中使用泛型类处理异步数据

一个使用泛型类定义数据状态并根据当前状态返回小部件的实现。

1. 初始数据声明

Ds<Profile> profileInfo = Loading(); // or Loading<Profile>();

2. 获取数据

Future<void> fetchData() async {  
  try {  
    profileInfo = Fetched(  
      User(  
        imgUrl: 'https://avatars.githubusercontent.com/u/75591730?v=4',  
        name: 'Ximya',  
        description:  
            'Lorem ipsum dolor sit amet, consectetur adipiscing ...',  
      ),  
    ); 
    log('Data successfully fetched');  
  } catch (e) {  
    profileInfo = Failed(e);  
    log('Data fetching failed. ${e}');  
  }  
}

3. 根据状态返回小部件

final profile = controller.profileInfo;

return profile.onState(  
  fetched: (value) => ProfileCard(value),  
  failed: (e) => ErrorIndicator(e),  
  loading: () => CircularProgressIndicator(),  
);

基本模块

sealed class Ds<T> {
  Ds({required this.state, this.error, this.valueOrNull});

  T? valueOrNull;
  Object? error;
  DataState state;

  T get value => valueOrNull!;

  R onState<R>({
    required R Function(T data) fetched,
    required R Function(Object error) failed,
    required R Function() loading,
  }) {
    if (state.isFailed) {
      return failed(error!);
    } else if (state.isLoading) {
      return loading();
    } else {
      return fetched(valueOrNull as T);
    }
  }
}

class Fetched<T> extends Ds<T> {
  final T data;

  Fetched(this.data) : super(state: DataState.fetched, valueOrNull: data);
}

class Loading<T> extends Ds<T> {
  Loading() : super(state: DataState.loading);
}

class Failed<T> extends Ds<T> {
  final Object error;

  Failed(this.error) : super(state: DataState.failed, error: error);
}

enum DataState {
  fetched,
  loading,
  failed;

  bool get isFetched => this == DataState.fetched;

  bool get isLoading => this == DataState.loading;

  bool get isFailed => this == DataState.failed;
}

GitHub

查看 Github