搜索插件、代码仓与 APP 分类

插件详情v0.10.0

flutter_redux

一组实用的 Widget,用于提供和连接到 Redux 存储

AndroidiOSWebmacOSWindowsLinux
近 30 天下载
5.6万
喜欢数
572
Pub 分数
160

安装插件

flutter pub add flutter_redux

插件介绍

基于插件公开信息、社区数据与项目使用情况整理的选型参考。

flutter_redux 是一个 Flutter 包,提供实用的组件来将 UI 组件连接到 Redux 存储,从而在 Flutter 应用中实现可预测的状态管理。它提供了 `StoreProvider`、`StoreBuilder` 和 `StoreConnector` 组件,以便轻松访问和响应整个组件树中的状态变化。专为使用 Redux 模式的开发者设计,通过集中管理应用状态和操作,促进关注点分离。该包与 Dart 的响应式编程模型无缝集成,并支持所有主要平台,包括 Android、iOS、Web、macOS、Windows 和 Linux。

适合场景

  • 管理全局应用状态
  • 实现单向数据流
  • 连接UI到Redux存储
  • 构建可扩展的 Flutter 应用
  • 独立测试状态逻辑

主要特点

  • StoreProvider 用于依赖注入
  • StoreBuilder 用于响应式状态更新
  • StoreConnector 用于细粒度的状态订阅
  • 对中间件和还原器的支持
  • 跨平台兼容性

适合对象

  • 大规模 Flutter 应用
  • 使用 Redux 架构的团队
  • 需要集中式状态管理的应用程序
  • 熟悉 Redux 模式的开发者
  • 需要可测试状态逻辑的项目

使用建议

  • 需要了解 Redux 概念
  • 与更简单的状态解决方案相比,可能会增加样板代码
  • 不适合小型或简单的应用
  • 频繁状态更新带来的性能影响
  • 初学者的学习曲线更陡峭

原始 README

以下为关联源码仓库的 README 原文快照,最新内容请访问源码仓库。

flutter_redux

Build Status codecov

A set of utilities that allow you to easily consume a Redux Store to build Flutter Widgets.

This package supports null-safety and is built to work with Redux.dart 5.0.0+ and Flutter 3+.

Redux Widgets

  • StoreProvider - The base Widget. It will pass the given Redux Store to all descendants that request it.
  • StoreBuilder - A descendant Widget that gets the Store from a StoreProvider and passes it to a Widget builder function.
  • StoreConnector - A descendant Widget that gets the Store from the nearest StoreProvider ancestor, converts the Store into a ViewModel with the given converter function, and passes the ViewModel to a builder function. Any time the Store emits a change event, the Widget will automatically be rebuilt. No need to manage subscriptions!

Examples

  • Simple example - a port of the standard "Counter Button" example from Flutter
  • Github Search - an example of how to search as a user types, demonstrating both the Middleware and Epic approaches.
  • Todo app - a more complete example, with persistence, routing, and nested state.
  • Timy Messenger - large open source app that uses flutter_redux together with Firebase Firestore.
Companion Libraries

Usage

Let's demo the basic usage with the all-time favorite: A counter example!

Note: This example requires flutter_redux 0.4.0+ and Dart 2! If you're using Dart 1, see the old example.

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

// One simple action: Increment
enum Actions { Increment }

// The reducer, which takes the previous count and increments it in response
// to an Increment action.
int counterReducer(int state, dynamic action) {
  return action == Actions.Increment ? state + 1 : state;
}

void main() {
  // Create your store as a final variable in the main function or inside a
  // State object. This works better with Hot Reload than creating it directly
  // in the `build` function.
  final store = Store<int>(counterReducer, initialState: 0);

  runApp(FlutterReduxApp(
    title: 'Flutter Redux Demo',
    store: store,
  ));
}

class FlutterReduxApp extends StatelessWidget {
  final Store<int> store;
  final String title;

  FlutterReduxApp({Key key, this.store, this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // The StoreProvider should wrap your MaterialApp or WidgetsApp. This will
    // ensure all routes have access to the store.
    return StoreProvider<int>(
      // Pass the store to the StoreProvider. Any ancestor `StoreConnector`
      // Widgets will find and use this value as the `Store`.
      store: store,
      child: MaterialApp(
        theme: ThemeData.dark(),
        title: title,
        home: Scaffold(
          appBar: AppBar(title: Text(title)),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                // Connect the Store to a Text Widget that renders the current
                // count.
                //
                // We'll wrap the Text Widget in a `StoreConnector` Widget. The
                // `StoreConnector` will find the `Store` from the nearest
                // `StoreProvider` ancestor, convert it into a String of the
                // latest count, and pass that String  to the `builder` function
                // as the `count`.
                //
                // Every time the button is tapped, an action is dispatched and
                // run through the reducer. After the reducer updates the state,
                // the Widget will be automatically rebuilt with the latest
                // count. No need to manually manage subscriptions or Streams!
                StoreConnector<int, String>(
                  converter: (store) => store.state.toString(),
                  builder: (context, count) {
                    return Text(
                      'The button has been pushed this many times: $count',
                      style: Theme.of(context).textTheme.display1,
                    );
                  },
                )
              ],
            ),
          ),
          // Connect the Store to a FloatingActionButton. In this case, we'll
          // use the Store to build a callback that will dispatch an Increment
          // Action.
          //
          // Then, we'll pass this callback to the button's `onPressed` handler.
          floatingActionButton: StoreConnector<int, VoidCallback>(
            converter: (store) {
              // Return a `VoidCallback`, which is a fancy name for a function
              // with no parameters and no return value. 
              // It only dispatches an Increment action.
              return () => store.dispatch(Actions.Increment);
            },
            builder: (context, callback) {
              return FloatingActionButton(
                // Attach the `callback` to the `onPressed` attribute
                onPressed: callback,
                tooltip: 'Increment',
                child: Icon(Icons.add),
              );
            },
          ),
        ),
      ),
    );
  }
}

Purpose

One question that reasonable people might ask: Why do you need all of this if StatefulWidget exists?

My advice is the same as the original Redux.JS author: If you've got a simple app, use the most straightforward thing possible. In Flutter, StatefulWidget is perfect for a simple counter app.

However, say you have the more complex app, such as an E-commerce app with a Shopping Cart. The Shopping Cart should appear on multiple screens in your app and should be updated by many different types of Widgets on those different screens (An "Add Item to Cart" Widget on all your Product Screens, "Remove Item from Cart" Widget on the Shopping Cart Screen, "Change quantity" Widgets, etc.).

Additionally, you want to test this logic, as it's the core business logic to your app!

Now, in this case, you could create a Testable ShoppingCart class as a Singleton or Create a Root StatefulWidget that passes the ShoppingCart Down Down Down through your widget hierarchy to the "add to cart" or "remove from cart" Widgets.

Singletons can be problematic for testing, and Flutter doesn't have a great Dependency Injection library (such as Dagger2) just yet, so I'd prefer to avoid those.

Yet passing the ShoppingCart all over the place can get messy. It also means

it's way harder to move that "Add to Item" button to a new location b/c you'd need up update the Widgets throughout your app that passes the state down.

Furthermore, you'd need a way to Observe when the ShoppingCart Changes so you could rebuild your Widgets when it does (from an "Add" button to an "Added" button, as an example).

One way to handle it would be to simply setState every time the ShoppingCart changes in your Root Widget, but then your whole app below the RootWidget would be required to rebuild as well! Flutter is fast, but we should be thoughtful about what we ask Flutter to rebuild!

Therefore, redux & redux_flutter was born for more complex stories like this one. It gives you a set of tools that allow your Widgets to dispatch actions in a naive way, then writes the business logic in another place that will take those actions and update the ShoppingCart in a safe, testable way.

Even more, once the ShoppingCart has been updated in the Store, the Store will emit an onChange event. This lets you listen to Store updates and rebuild your UI in the right places when it changes! Now, you can separate your business logic from your UI logic in a testable, observable way, without having to Wire up a bunch of stuff yourself!

Similar patterns in Android are the MVP Pattern or using Rx Observables to manage a View's State.

flutter_redux handles passing your Store down to all of your descendant StoreConnector Widgets. If your State emits a change event, only the StoreConnector Widgets and their descendants will be automatically rebuilt with the latest State of the Store!

This allows you to focus on what your app should look like and how it should work without thinking about all the glue code to hook everything together!

Contributors

所属分类

依赖

依赖清单 1 项

源码仓库

使用此插件的项目

所在榜单