Flutter异步状态管理与Redux结合插件flutter_hooks_async_redux的使用

发布于 1周前 作者 yibo5220 来自 Flutter

Flutter异步状态管理与Redux结合插件flutter_hooks_async_redux的使用

添加Redux到Flutter Hooks

这个包结合了 flutter_hooksasync_redux 包,为Flutter应用程序提供了Redux模式的状态管理能力。通过它,你可以更方便地使用函数式编程的方式管理应用状态。

依赖配置

为了使用此包,你需要在pubspec.yaml中添加以下依赖:

dependencies:
  flutter_hooks: ^0.20.5 # 或更新版本
  async_redux: ^24.0.0 # 或更新版本
  flutter_hooks_async_redux: ^1.0.3 # 或更新版本

安装后,你就可以享受Flutter Hooks和Async Redux的所有特性了。

提供的Hook函数

useSelector

useSelector允许你选择部分状态并订阅其更新。给定一个从全局状态映射到所需状态片段的函数作为参数,例如:

String username = useSelector<AppState, String>((state) => state.username);

如果你的状态类名为AppState,可以通过定义自己的useAppState钩子简化访问:

T useAppState<T>(T Function(AppState state) converter, {bool distinct = true}) =>
    useSelector<AppState, T>(converter, distinct: distinct);

// 使用示例
String username = useAppState((state) => state.username);

useDispatch

useDispatch用于分发动作,执行相应的reducer逻辑,并可能改变store中的状态。它可以处理同步或异步的动作:

var dispatch = useDispatch();
dispatch(MyAction());

useDispatchAndWait

useDispatchAndWait不仅分发动作,还会返回一个Future对象,在动作完成时解析。这对于处理需要等待结果的异步操作非常有用:

var dispatchAndWait = useDispatchAndWait();
await dispatchAndWait(DoThisFirstAction());

注意:虽然动作的reducer逻辑会在Future解析前完成,但由动作启动的其他独立进程可能仍在进行中。

useDispatchSync

useDispatchSyncuseDispatch类似,但它不允许分发异步动作,否则会抛出异常。

useIsWaiting

useIsWaiting可以用来检查特定类型的动作是否正在被处理,或者是否有任何给定的动作类型正在等待完成。这有助于显示加载指示器等UI反馈:

var isWaiting = useIsWaiting(MyAction);
if (isWaiting) {
  // 显示加载图标
}

useIsFailed、useExceptionFor、useClearExceptionFor

这些方法可以帮助我们检测某个动作是否失败,获取具体的错误信息以及清除指定动作的异常记录:

var isFailed = useIsFailed(MyAction);
if (isFailed) {
  // 显示错误信息
}

var exception = useExceptionFor(MyAction);
Text(exception!.reason ?? '');

var clearExceptionFor = useClearExceptionFor();
clearExceptionFor(MyAction);

示例代码

下面是一个完整的示例应用,展示了如何结合使用上述功能来构建一个简单的计数器应用:

import 'package:async_redux/async_redux.dart';
import 'package:flutter/material.dart' hide Action;
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
import 'package:flutter_hooks_async_redux/flutter_hooks_async_redux.dart';

class AppState {
  final int counter;

  const AppState({this.counter = 0});
}

T useAppState<T>(T Function(AppState state) converter, {bool distinct = true}) =>
    useSelector<AppState, T>(converter, distinct: distinct);

void main() {
  runApp(
    MaterialApp(
      home: StoreProvider<AppState>(
        store: Store<AppState>(initialState: const AppState()),
        child: const Application(),
      ),
    ),
  );
}

class Application extends HookWidget {
  const Application({super.key});

  @override
  Widget build(BuildContext context) {
    final dispatch = useDispatch();
    int counter = useAppState((state) => state.counter);
    var isWaitingIncrement = useIsWaiting(IncrementAction);

    useEffect(() {
      dispatch(SetCounter(42));
    }, []);

    return Scaffold(
      body: Center(
        child: Text('Counter is $counter'),
      ),
      floatingActionButton: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          FloatingActionButton(
            disabledElevation: 0,
            onPressed: isWaitingIncrement ? null : () => dispatch(IncrementAction()),
            child: isWaitingIncrement ? const CircularProgressIndicator() : const Icon(Icons.add),
          ),
          const SizedBox(height: 12),
          FloatingActionButton(
            child: const Icon(Icons.clear),
            onPressed: () {
              dispatch(ResetCounter());
            },
          ),
        ],
      ),
    );
  }
}

class IncrementAction extends ReduxAction<AppState> {
  @override
  Future<AppState?> reduce() async {
    await Future.delayed(const Duration(milliseconds: 500));
    return AppState(counter: state.counter + 1);
  }
}

class SetCounter extends ReduxAction<AppState> {
  final int value;

  SetCounter(this.value);

  @override
  AppState reduce() => AppState(counter: value);
}

class ResetCounter extends ReduxAction<AppState> {
  @override
  AppState reduce() {
    return const AppState();
  }
}

在这个例子中,我们创建了一个包含计数器的应用程序,用户可以通过点击按钮增加计数器的值。当点击“+”按钮时,如果当前正在进行增量操作,则按钮将变为不可用,并显示进度条;而点击“清除”按钮则会重置计数器。


更多关于Flutter异步状态管理与Redux结合插件flutter_hooks_async_redux的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter异步状态管理与Redux结合插件flutter_hooks_async_redux的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter中,结合异步状态管理与Redux可以显著提升应用的状态管理效率和响应速度。flutter_hooks_async_redux是一个强大的插件,它允许我们使用Flutter Hooks与Redux进行异步状态管理。以下是一个使用flutter_hooks_async_redux的示例代码案例,展示了如何设置和使用这个插件。

首先,确保你的pubspec.yaml文件中已经添加了必要的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_redux: ^0.6.0 # 确保使用兼容的版本
  redux: ^4.0.0 # 确保使用兼容的版本
  flutter_hooks: ^0.18.0 # 确保使用兼容的版本
  hooks_riverpod: ^1.0.0 # 如果你使用Riverpod作为依赖注入容器
  flutter_hooks_async_redux: ^x.y.z # 替换为最新版本号

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

接下来,我们创建一个简单的Redux store。假设我们有一个计数器应用,并且希望异步增加计数器的值。

创建Redux Store

import 'package:redux/redux.dart';

// 定义Action类型
enum CounterAction { incrementAsync }

// 定义Action类
class CounterActions {
  static final incrementAsync = CounterAction.incrementAsync;
}

// 定义Action Creator
dynamic counterReducer(dynamic state, action) {
  if (state == null) return 0;

  switch (action) {
    case CounterAction.incrementAsync:
      // 这里我们仅做同步处理,异步逻辑将在Middleware中处理
      return state + 1;
    default:
      return state;
  }
}

// 创建Store
final Store<int> store = Store<int>(
  counterReducer,
  initialState: 0,
  middleware: [
    // 在这里添加异步Middleware,例如使用redux_thunk
  ],
);

使用flutter_hooks_async_redux

接下来,我们在Flutter组件中使用flutter_hooks_async_redux。为了简化示例,这里不添加真正的异步Middleware,而是模拟一个异步操作。

import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_hooks_async_redux/flutter_hooks_async_redux.dart';

void main() {
  runApp(StoreProvider<int>(store: store, child: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Flutter Async Redux Example')),
        body: Center(
          child: MyCounter(),
        ),
      ),
    );
  }
}

class MyCounter extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final count = useSelector((state) => state);
    final dispatch = useDispatch();

    useEffect(() {
      // 模拟异步操作,例如使用Future.delayed
      Future.delayed(Duration(seconds: 2)).then((_) {
        dispatch(CounterActions.incrementAsync);
      });
    }, []); // 空依赖数组表示只在组件挂载时执行一次

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text(
          'You have pushed the button this many times:',
        ),
        Text(
          '$count',
          style: Theme.of(context).textTheme.headline4,
        ),
      ],
    );
  }
}

在这个示例中,我们使用了flutter_hooksuseSelectoruseDispatch钩子来分别获取Redux store的状态和分发动作。useEffect钩子用于模拟一个异步操作,它在组件挂载后2秒触发一次计数器的增加动作。

注意:在实际应用中,你应该在Redux Middleware中处理异步逻辑,而不是在组件内部使用Future.delayed。这里只是为了简化示例。

这个示例展示了如何将flutter_hooks_async_redux与Flutter和Redux结合使用来进行异步状态管理。希望这对你有所帮助!

回到顶部