Flutter Redux中间件插件typed_redux_epics的使用

Flutter Redux中间件插件typed_redux_epics的使用

简介

typed_redux_epicsdart_redux_epics 的类型安全版本。它允许你在 Redux 应用程序中使用 Epic 中间件来处理异步操作,并且提供了更好的类型支持。

感谢原作者的灵感!


使用示例

以下是一个完整的示例,展示如何在 Flutter 中使用 typed_redux_epics 插件。

1. 添加依赖

首先,在你的 pubspec.yaml 文件中添加 typed_redux_epics 依赖:

dependencies:
  flutter:
    sdk: flutter
  redux: ^6.0.0
  typed_redux: ^2.0.0
  typed_redux_epics: ^2.0.0

然后运行 flutter pub get 安装依赖。


2. 创建 Action 和 State

定义你的 Redux Action 和 State 类型。例如:

// actions.dart
enum TodoActionType { ADD_TODO, REMOVE_TODO }

class AddTodoAction {
  final String text;
  AddTodoAction(this.text);
}

class RemoveTodoAction {
  final int id;
  RemoveTodoAction(this.id);
}

3. 创建 Epic

Epic 是一个函数,接收 Actions 并返回一个新的 Stream 或 Iterable。

// epics.dart
import 'dart:async';
import 'package:redux/redux.dart';
import 'package:typed_redux_epics/typed_redux_epics.dart';

Future<Stream<dynamic>> fetchTodos(EpicStore store, dynamic action, NextDispatcher next) async {
  // 模拟异步操作
  await Future.delayed(Duration(seconds: 2));

  if (action is AddTodoAction) {
    return Stream.value(AddTodoAction(action.text + " (Fetched)"));
  }
  return Stream.empty();
}

final todoEpic = TypedEpic<dynamic, dynamic>(fetchTodos);

4. 配置 Store

将 Epic 注册到 Redux Store 中。

// store.dart
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:typed_redux_epics/typed_redux_epics.dart';
import 'actions.dart';
import 'epics.dart';
import 'reducers.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return StoreProvider(
      store: _createStore(),
      child: MaterialApp(
        title: 'Typed Redux Epics Example',
        home: MyHomePage(),
      ),
    );
  }

  Store<AppState> _createStore() {
    final todoEpic = TypedEpic<dynamic, dynamic>(fetchTodos);

    return Store<AppState>(
      appReducer,
      initialState: AppState.initial(),
      middleware: [
        TypedMiddleware<dynamic, dynamic>(todoEpic),
      ],
    );
  }
}

5. 编写 Reducer

Reducer 负责处理 Action 并更新 State。

// reducers.dart
import 'package:redux/redux.dart';
import 'actions.dart';

class AppState {
  final List<String> todos;

  AppState({required this.todos});

  factory AppState.initial() => AppState(todos: []);

  AppState copyWith({List<String>? todos}) =>
      AppState(todos: todos ?? this.todos);
}

AppState appReducer(AppState state, dynamic action) {
  if (action is AddTodoAction) {
    return state.copyWith(todos: [...state.todos, action.text]);
  } else if (action is RemoveTodoAction) {
    return state.copyWith(todos: state.todos.where((t) => t != action.id).toList());
  }
  return state;
}

6. 显示 UI

创建一个简单的 UI 来显示 Todos 列表。

// my_home_page.dart
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:example/actions.dart'; // 替换为实际路径
import 'package:example/store.dart'; // 替换为实际路径

class MyHomePage extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return StoreConnector<AppState, _ViewModel>(
      converter: _ViewModel.fromStore,
      builder: (context, vm) {
        return Scaffold(
          appBar: AppBar(title: Text('Typed Redux Epics Example')),
          body: ListView.builder(
            itemCount: vm.todos.length,
            itemBuilder: (context, index) {
              return ListTile(
                title: Text(vm.todos[index]),
                trailing: IconButton(
                  icon: Icon(Icons.delete),
                  onPressed: () => vm.removeTodo(index),
                ),
              );
            },
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () => vm.addTodo("New Todo"),
            child: Icon(Icons.add),
          ),
        );
      },
    );
  }
}

class _ViewModel {
  final List<String> todos;
  final Function(int) removeTodo;
  final Function(String) addTodo;

  _ViewModel({
    required this.todos,
    required this.removeTodo,
    required this.addTodo,
  });

  static _ViewModel fromStore(Store<AppState> store) {
    return _ViewModel(
      todos: store.state.todos,
      removeTodo: (index) => store.dispatch(RemoveTodoAction(index)),
      addTodo: (text) => store.dispatch(AddTodoAction(text)),
    );
  }
}

更多关于Flutter Redux中间件插件typed_redux_epics的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Redux中间件插件typed_redux_epics的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


typed_redux_epics 是一个用于 Flutter 和 Dart 的 Redux 中间件插件,它允许你使用 Epics 来处理异步操作。Epics 是一种基于流的中间件,通常用于处理复杂的异步逻辑,例如 API 调用、定时任务等。

安装

首先,你需要在 pubspec.yaml 文件中添加 typed_redux_epics 依赖:

dependencies:
  flutter:
    sdk: flutter
  redux: ^5.0.0
  typed_redux_epics: ^0.2.1

然后运行 flutter pub get 来安装依赖。

基本使用

1. 定义 Actions

首先,定义你的 Redux actions:

class FetchDataAction {}

class DataFetchedAction {
  final List<String> data;

  DataFetchedAction(this.data);
}

class FetchDataErrorAction {
  final String error;

  FetchDataErrorAction(this.error);
}

2. 定义 Reducer

接下来,定义你的 Reducer 来处理这些 actions:

AppState appReducer(AppState state, dynamic action) {
  if (action is DataFetchedAction) {
    return state.copyWith(data: action.data, isLoading: false);
  } else if (action is FetchDataErrorAction) {
    return state.copyWith(error: action.error, isLoading: false);
  } else if (action is FetchDataAction) {
    return state.copyWith(isLoading: true);
  }
  return state;
}

3. 定义 Epic

Epic 是一个函数,它接收一个 Stream<Action> 并返回一个 Stream<Action>。你可以使用 typed_redux_epics 来处理异步操作:

import 'package:typed_redux_epics/typed_redux_epics.dart';
import 'package:redux/redux.dart';
import 'package:rxdart/rxdart.dart';

Stream<dynamic> fetchDataEpic(Stream<dynamic> actions, EpicStore<AppState> store) {
  return actions
      .whereType<FetchDataAction>()
      .asyncMap((action) async {
        try {
          // 模拟 API 调用
          await Future.delayed(Duration(seconds: 2));
          return DataFetchedAction(['Item 1', 'Item 2', 'Item 3']);
        } catch (e) {
          return FetchDataErrorAction(e.toString());
        }
      });
}

4. 创建 Store

在创建 Redux store 时,将 Epic 中间件添加到 store 中:

import 'package:redux/redux.dart';
import 'package:typed_redux_epics/typed_redux_epics.dart';

final epicMiddleware = EpicMiddleware<AppState>(fetchDataEpic);

final store = Store<AppState>(
  appReducer,
  initialState: AppState.initial(),
  middleware: [epicMiddleware],
);

5. 在 Flutter 中使用 Store

最后,你可以在 Flutter 中使用 StoreProviderStoreConnector 来连接 Redux store:

import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return StoreProvider(
      store: store,
      child: MaterialApp(
        home: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Redux Epic Example'),
      ),
      body: StoreConnector<AppState, ViewModel>(
        converter: (Store<AppState> store) => ViewModel.create(store),
        builder: (context, vm) {
          if (vm.isLoading) {
            return Center(child: CircularProgressIndicator());
          } else if (vm.error != null) {
            return Center(child: Text('Error: ${vm.error}'));
          } else {
            return ListView(
              children: vm.data.map((item) => ListTile(title: Text(item))).toList(),
            );
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          store.dispatch(FetchDataAction());
        },
        child: Icon(Icons.refresh),
      ),
    );
  }
}

class ViewModel {
  final bool isLoading;
  final String error;
  final List<String> data;

  ViewModel({this.isLoading, this.error, this.data});

  static ViewModel create(Store<AppState> store) {
    return ViewModel(
      isLoading: store.state.isLoading,
      error: store.state.error,
      data: store.state.data,
    );
  }
}
回到顶部