flutter-状态管理5-Redux

作者: 浮华_du | 来源:发表于2021-04-19 17:06 被阅读0次

    这个相对来说比较复杂

    1. 先看例子

    • 需要引入的库
      redux: ^5.0.0
      #添加支持异步操作的支持库
      redux_thunk: ^0.4.0
    

    1.建立State

    • 建立一个共享数据,并提供构造方法
    class CountState {
      int _count;
      get count => _count;
      CountState(this._count);
      CountState.initState() : _count = 0;
    }
    

    2.创建Action

    • 建立Actions操作数据,这里是定义两个事件: 加 减
    enum Actions { increment, decrement }
    
    class Action {
      final Actions type;
      Action(this.type);
    }
    
    class IncreTestAction extends Action {
      int value;
      IncreTestAction(this.value) : super(Actions.increment);
    }
    
    class DecreTestAction extends Action {
      int value;
      DecreTestAction(this.value) : super(Actions.decrement);
    }
    

    3.创建Action对应的reducer

    • 创建action动作对应的reducer,返回State
    • 将action合并,以便启动入口处使用
    • 另外,我们这里还定义了一个异步的加法
    ///创建reducer
    CountState increReducer(CountState preState, dynamic action) {
      switch (action.type) {
        case Actions.increment:
          return CountState(preState.count + action.value);
        default:
          return preState;
      }
    }
    
    CountState decreReducer(CountState preState, dynamic action) {
      switch (action.type) {
        case Actions.decrement:
          return CountState(preState.count - action.value);
        default:
          return preState;
      }
    }
    
    /// 合并reducer
    final reducers = combineReducers([increReducer, decreReducer]);
    
    /// 异步加
    ThunkAction asyncIncrement(int value) {
      return (Store store) async {
        await Future.delayed(Duration(seconds: 3));
        store.dispatch(IncreTestAction(value));
      };
    }
    
    

    4.创建中间件

    • 创建一个产生中间件的工厂类
    • 通过new TypedMiddleware的方式创建中间件
    • 创建一个异步处理的中间件俩处理我们的Thunk类型的函数
    • 把所有的中间件集合到一起,以便启动入口处使用
    ///第一步 创建一个产生中间件的工厂类,
    ///利用generate产生中间件
    abstract class MiddlewareFactory {
      MiddlewareFactory();
    
      List<Middleware<CountState>> generate();
    }
    
    class LoggerMiddle extends MiddlewareFactory {
      @override
      List<Middleware<CountState>> generate() {
        // TODO: implement generate
        ///第二步 通过new TypedMiddleware的方式创建中间件
        return [
          TypedMiddleware<CountState, IncreTestAction>(_doIncreLogger),
          TypedMiddleware<CountState, DecreTestAction>(_doDecreLogger),
        ];
      }
    
      void _doIncreLogger(
          Store<CountState> store, IncreTestAction action, NextDispatcher next) {
        next(action);
        debugPrint(
            "store:${store.state.count}, action type ${action.type}, value ${action.value}");
      }
    
      void _doDecreLogger(
          Store<CountState> store, DecreTestAction action, NextDispatcher next) {
        next(action);
        debugPrint(
            "store:${store.state.count}, action type ${action.type}, value ${action.value}");
      }
    }
    
    class ThunkMiddle extends MiddlewareFactory {
      @override
      List<Middleware<CountState>> generate() {
        // TODO: implement generate
        return [
          /// 创建一个异步处理的中间件俩处理我们的Thunk类型的函数
          TypedMiddleware<CountState, ThunkAction>(_doThunk),
        ];
      }
    
      void _doThunk(
          Store<CountState> store, ThunkAction action, NextDispatcher next) {
        if (action is ThunkAction<CountState>) {
          action(store);
        } else {
          next(action);
        }
      }
    }
    
    
    ///第三步 把所有的中间件集合到一起
    List<Middleware<CountState>> initMiddleware() {
      List<Middleware<CountState>> middlewares = [];
      List<MiddlewareFactory> factories = [
        LoggerMiddle(),
        ///第三步,一起放入到中间件集合
        ThunkMiddle(),
      ];
      factories.forEach((factory) => middlewares.addAll(factory.generate()));
      return middlewares;
    }
    

    5.runApp时初始化Store

    • 使用前面创建的reducer 和 中间件,并使用StoreProvider包裹
    void main() {
          Store store = Store<CountState>(reducers,
                  initialState: CountState.initState(), middleware:initMiddleware());
          runApp(StoreProvider<CountState>(
                store: store,
                child: MyApp() )
        );
    }
    

    6.页面内测试使用

    1.用于展示 , 操作数据的widget
    • 使用StoreConnector获取store,进而可以拿到里面的state,拿到共享数据
    /// 展示数值
    class StoreConnectorTextWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        ///获取store的state
        print("StoreConnector展示__build");
        return StoreConnector<CountState, int>(
          converter: (store) => store.state.count,
          builder: (context, vm) {
            print("StoreConnector展示__刷新");
            return Text(
              "Count: $vm",
              style: TextStyle(fontSize: 30),
            );
          },
        );
      }
    //   StoreConnector<S, ViewModel>
    // 首先这里需要强制声明类型,S代表我们需要从store中获取什么类型的state,ViewModel指的是我们使用这个State时的实际类型。
    // 然后我们需要声明一个converter<S,ViewModel>,它的作用是将Store转化成实际ViewModel将要使用的信息,比如我们这里实际上要使用的是count,所以这里将count提取出来。
    // builder是我们实际根据state创建Widget的地方,它接收一个上下文context,以及刚才我们转化出来的ViewModel,所以我们就只需要把拿到的count放进Text Widget中进行渲染就好了
    
    }
    
    • 使用StoreConnector或者StoreBuilder,获取store,可以通过store.dispatch发送Action事件,修改数据
    //加
    class StoreConnectorAddButtonWidget extends StatelessWidget {
      final String text;
      final int value;
      StoreConnectorAddButtonWidget(this.text, this.value) : super();
    
      @override
      Widget build(BuildContext context) {
        print("StoreConnector_+操作__build");
        return StoreConnector<CountState, VoidCallback>(
          converter: (Store<CountState> store) {
            return () => store.dispatch(IncreTestAction(value)); //发送加value的action
          },
          builder: (context, callback) {
            print("StoreConnector__+操作_刷新");
            return TextButton(
              child: Text(text),
              onPressed: callback,
            );
          },
        );
      }
    // 我们还是使用StoreConnector<S,ViewModel>。
    // 这里由于是发出了一个动作,所以是VoidCallback。
    // store.dispatch发起一个action,任何中间件都会拦截该操作,在运行中间件后,操作将被发送到给定的reducer生成新的状态,并更新状态树。
    
    }
    
    
    //减
    class StoreConnectorDecreButtonWidget extends StatelessWidget {
      final String text;
      final int value;
      StoreConnectorDecreButtonWidget(this.text, this.value) : super();
    
      @override
      Widget build(BuildContext context) {
        return StoreBuilder<CountState>(builder: (context, store) {
          return TextButton(
              child: Text(text),
              onPressed: () {
                store.dispatch(DecreTestAction(value));
              });
        });
        // return StoreConnector<CountState, VoidCallback>(
        //   converter: (Store<CountState> store) {
        //     return () => store.dispatch(DecreTestAction(value)); //发送减value的action
        //   },
        //   builder: (context, callback) {
        //     return TextButton(
        //       child: Text(text),
        //       onPressed: callback,
        //     );
        //   },
        // );
      }
    }
    
    /// 异步加
    class AsyncAddButton extends StatelessWidget {
      final String text;
      final int value;
      AsyncAddButton(this.text, this.value) : super();
    
      @override
      Widget build(BuildContext context) {
        print("StoreConnector_异步操作__build");
        return StoreConnector<CountState, VoidCallback>(
          converter: (Store<CountState> store) {
            return () => store.dispatch(asyncIncrement(value)); //发送异步加value的action
          },
          builder: (context, callback) {
            print("StoreConnector_异步操作__刷新");
            return TextButton(
              child: Text(text),
              onPressed: callback,
            );
          },
        );
      }
    }
    
    2.测试页面
    • 展示数据,修改数据,异步修改数据
    class ReduxFirstPage extends StatelessWidget {
      final String title;
    
      ReduxFirstPage(this.title) : super();
    
      @override
      Widget build(BuildContext context) {
        print("Redux__first_build");
        return Scaffold(
            appBar: AppBar(
              title: Text(title),
            ),
            body: ListView(
              children: [
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: StoreConnectorTextWidget(),
                ),
                TextButton(
                  child: Text("跳转到第二页"),
                  onPressed: () {
                    Navigator.of(context)
                        .push(MaterialPageRoute(builder: (BuildContext context) {
                      return ReduxtSecondPage("第二页");
                    }));
                    debugPrint("跳转到第二页");
                  },
                ),
                AsyncAddButton("异步加二  3s后", 2),
              ],
            ));
      }
    }
    
    class ReduxtSecondPage extends StatelessWidget {
      final String title;
    
      ReduxtSecondPage(this.title) : super();
    
      @override
      Widget build(BuildContext context) {
        print("redux__second_build");
        return Scaffold(
            appBar: AppBar(
              title: Text(title),
            ),
            body: Container(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: StoreConnectorTextWidget(),
                  ),
                  StoreConnectorAddButtonWidget("加一", 1),
                  StoreConnectorAddButtonWidget("加二", 2),
                  StoreConnectorDecreButtonWidget("减一", 1),
                  StoreConnectorDecreButtonWidget("减二", 2),
                ],
              ),
            ));
      }
    }
    

    感兴趣的话,大家可以试试.
    下面,我们来分析下Redux实现状态管理的原理:

    2.Redux原理

    1.StoreProvider
    • 根据翻译可以了解到, 它可以向它所有的子类提供Redux[Store],子类中使用[StoreConnector]或[StoreBuilder]拿到到它提供的共享数据.
    • 初始化需要传入一个store
    • 另外,它是一个inheritedWidget.
      内部也给出了一个例子,可以通过其内部提供的of方法获取到store,进而拿到共享数据.
      Store<String> store = StoreProvider.of<String>(context, listen: true);
    StoreProvider.png
    2.Store的创建
    • 需要传入一个reducer 、 initialState、middleware中间件函数或列表
      reducer: 指定应如何更改状态以响应已调度的操作
      initialState: 定义了首次创建存储时存储的状态
      middleware: 在action到达reducer之前,拦截action,并可以改变数据
    3.StoreConnector
    • converter:可以使用它获取store,获取原理依然是使用StoreProvider.of方法


      image.png
    image.png
    image.png

    (1) StoreConnector<CountState, int>,通过store.state.count,拿到共享数据<=>ViewModel,返回数据
    (2) StoreConnector<CountState, VoidCallback>通过store.dispatch方法,分发action, 并返回VoidCallback
    (3)store.dispatch内部实现可以知道,是拿到_dispatchers第0个,通过中间件执行这个action,然后使用给定的[Reducer]将Action应用于共享数据.


    image.png
    image.png
    image.png
    4.StoreBuilder

    StoreBuilder内部依然使用StoreConnector实现


    image.png

    相关文章

      网友评论

        本文标题:flutter-状态管理5-Redux

        本文链接:https://www.haomeiwen.com/subject/ypoelltx.html