搜尋分類、套件與程式碼儲存庫

套件詳情v8.0.0

provider_for_redux

允許您將 Provider 與 Redux 一起使用。使用 AsyncRedux,這是 Redux 的無樣板版本(https://pub.dev/packages/async_redux)。

AndroidiOSWebmacOSWindowsLinux
近 30 天下載
118
喜歡數
16
Pub 分數
150

安裝套件

flutter pub add provider_for_redux

套件介紹

根據套件公開資料產生的選型評估,僅供參考。

provider_for_redux 透過 AsyncRedux 实現 Provider 和 Redux 的無縫整合,AsyncRedux 是一個輕量級、無樣板程式碼的 Redux 實作。它讓開發者能夠利用 Provider 的簡單性進行依賴注入,同時享有 Redux 可預測的狀態管理優勢。此套件非常適合需要結構化狀態處理卻不希望編寫過多程式碼的應用程式。它支援所有主要平台,並透過非同步動作與不可變狀態模式簡化狀態更新。

適用情境

  • 結合 Provider 與 Redux 實現可擴展的狀態管理
  • 使用可預測的狀態流建構大型Flutter應用
  • 簡化複雜應用程式中的狀態邏輯
  • 使用 AsyncRedux 與 Provider 的反應式小部件
  • 將現有的 Redux 程式碼遷移到更乾淨的模式

主要特色

  • 將 Provider 與 AsyncRedux 集成
  • 與傳統的 Redux 相比,減少樣板程式碼
  • 支援非同步狀態更新
  • 提供類型安全的狀態與動作處理
  • 適用於所有 Flutter 平台

適合對象

  • 熟悉 Redux 的開發者
  • 需要結構化狀態管理的團隊
  • 需要同時具備依賴注入和狀態控制的專案
  • 具有複雜狀態邏輯的應用程式
  • 希望避免 Redux 開發重複程式碼的使用者

使用建議

  • 需要理解 Provider 和 Redux 概念
  • 可能為小型應用增加複雜性
  • 依賴 AsyncRedux,後者有其自身的學習曲線
  • 不建議用於簡單的狀態需求
  • 最適合中大型專案

原始 README

以下為關聯原始碼儲存庫的 README 原文快照,最新內容請造訪原始碼儲存庫。

pub package

provider_for_redux

With Provider you can inject your state, but it's your job to figure out how to update that state, structure the solution etc. In other words, Provider is a great alternative to InheritedWidget, and lets you do dependency injection, but you still need to do your own state management.

What people mean by “Provider as state management” is usually using Provider to do scoped model. But as a matter of fact, this is not the only possible architecture using Provider. You can use it with Bloc, Mobx, Redux and other.

This package lets you use it with AsyncRedux, the non-boilerplate version of Redux.

How to use it

Please, read the async_redux documentation first, if you haven't already.

You should have learned that to use AsyncRedux the traditional way, you provide the Redux store to your app by wrapping it with a StoreProvider, and then using the so called "connector" widgets, like the MyHomePageConnector below:

@override
Widget build(BuildContext context) =>
    StoreProvider<AppState>(
        store: store,
        child: MaterialApp(
          home: MyHomePageConnector(),
        ));

Now, if you want to use AsyncRedux with Provider, simply remove the StoreProvider and use AsyncReduxProvider instead. Also, you won't need the connector widgets anymore, since you will use Provider instead.

For example:

@override
Widget build(BuildContext context) =>
    AsyncReduxProvider<AppState>.value( // Instead of StoreProvider.
        value: store,
        child: MaterialApp(
          home: MyHomePage(), // Instead of MyHomePageConnector. 
        ));

The AsyncReduxProvider widget above will expose the store, the state, and the dispatch method to its descendants:

  • The Redux store, of type Store. Get it like this: Provider.of<Store<AppState>>(context).

  • The store's state, of type AppState. Get it like this: Provider.of<AppState>(context).

  • The dispatch method, of type Dispatch. Get it like this: Provider.of<Dispatch>(context).

This is a complete example:

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key}) : super(key: key);

  int counter(context) =>
      Provider
          .of<AppState>(context)
          .counter;

  String description(context) =>
      Provider
          .of<AppState>(context)
          .description;

  VoidCallback onIncrement(context) =>
          () => Provider.of<Dispatch>(context, listen: false)(IncrementAndGetDescriptionAction());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Increment Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text("You've pushed the button:"),
            Text('${counter(context)}', style: TextStyle(fontSize: 30)),
            Text('${description(context)}', style: TextStyle(fontSize: 15)),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: onIncrement(context),
        child: Icon(Icons.add),
      ),
    );
  }
}

Try running the Provider.of example.

Consumer

You can use Provider's Consumer class to read from the store. For example:

return Consumer<Store<AppState>>(
   builder: (context, store, child) =>
      ...
      Text('${store.state.counter}'),
      ...
      onPressed: () => store.dispatch(IncrementAction()),
),

But it's easier if you use ReduxConsumer, which already gives you the store, the state, and the dispatch method:

return ReduxConsumer<AppState>(
   builder: (context, store, state, dispatch, child) => ...

This is a complete example:

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ReduxConsumer<AppState>(
      builder: (context, store, state, dispatch, child) => Scaffold(
        appBar: AppBar(title: Text('Increment Example')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text("You've pushed the button:"),
              Text('${state.counter}', style: TextStyle(fontSize: 30)),
              Text('${state.description}', style: TextStyle(fontSize: 15)),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => dispatch(IncrementAndGetDescriptionAction()),
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

Try running the ReduxConsumer example.

Selector

You can use Provider's Selector class to read from the store, while preventing unnecessary widget rebuilds. For example:

return Selector<Store<AppState>, Tuple2<int, Dispatch>>(

   selector: (context, store) => 
      Tuple2(store.state.counter, store.dispatch),

   builder: (context, model, child) => 
      ...     
      Text('${model.item1}'),
      ...
      onPressed: () => model.item3(IncrementAction()),      
      ),

Your selector parameter must return a "model" which you can use to build your widget in the builder parameter. In the above example the model is a Tuple2 instance, but you can return any immutable object that correctly implements equals and hashcode. The widget will rebuild whenever the model changes.

But it's easier if you use ReduxSelector, which already gives you the store, the state, and the dispatch method:

return ReduxSelector<AppState, Tuple2<int, String>>(
selector: (context, state) => Tuple2(state.counter, store.dispatch),
builder: (ctx, store, state, dispatch, model, child) =>
   ...
   Text('${state.counter}'),
   ...
   onPressed: () => store.dispatch(IncrementAction()
   ),
),

Try running the ReduxSelector with model example.

However, ReduxSelector also lets you return a List as the model. In case you do that, it will rebuild the widget whenever any of the items in the list changes:

return ReduxSelector<AppState, dynamic>(
selector: (context, state) => [...],
builder: (context, store, state, dispatch, model, child) => ...    

Using ReduxSelector with a list is the easiest way of all, since you just need to list all of the state parts that should trigger a rebuild.

Note: The builder gives you both the state and the model, and you can choose one of them to build your widget from. While using state is probably easier for you, it's also easier to accidentally use something you forget to add to the model, and then wonder why the Widget doesn't rebuild. So you have two options:

  1. Use only the model and have the compiler make sure there's no state you're using from outside of the model.
  2. Use state directly, and have yourself the responsibility to make you've listed everything you' re using in the model.

This is a complete example:


Widget build(BuildContext context) {       
  return ReduxSelector<AppState, dynamic>(
     
      selector: (context, state) => [
                                    state.counter, 
                                    state.description
                                    ],

      builder: (context, store, state, dispatch, model, child) => 
         Scaffold(
             appBar: AppBar(title: Text('Increment Example')),
             body: Center(
               child: Column(
                 mainAxisAlignment: MainAxisAlignment.center,
                 children: [
                   Text("You've pushed the button:"),
                   Text('${state.counter}', style: TextStyle(fontSize: 30)),
                   Text('${state.description}', style: TextStyle(fontSize: 15)),
                 ],
               ),
             ),
             floatingActionButton: FloatingActionButton(
               onPressed: () => dispatch(IncrementAndGetDescriptionAction()),
               child: Icon(Icons.add),
             )));
}

Try running the ReduxSelector with list example.

Migrating

When you use AsyncReduxProvider you will notice that both Provider and AsyncRedux's StoreConnector will work simultaneously. You can mix and match both of them, as desired, or slowly migrate between them.


By Marcelo Glasberg

glasberg.dev
github.com/marcglasberg
linkedin.com/in/marcglasberg/
twitter.com/glasbergmarcelo
stackoverflow.com/users/3411681/marcg
medium.com/@marcglasberg

My article in the official Flutter documentation:

The Flutter packages I've authored:

My Medium Articles:

所屬分類

依賴

依賴清單 3 項

原始碼儲存庫

使用此套件的專案

暫無相關資料。