前端开发那些事儿Flutter

flutter-状态管理5-Redux

2021-04-19  本文已影响0人  浮华_du

这个相对来说比较复杂

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

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

///创建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.创建中间件

///第一步 创建一个产生中间件的工厂类,
///利用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

void main() {
      Store store = Store<CountState>(reducers,
              initialState: CountState.initState(), middleware:initMiddleware());
      runApp(StoreProvider<CountState>(
            store: store,
            child: MyApp() )
    );
}

6.页面内测试使用

1.用于展示 , 操作数据的widget
/// 展示数值
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中进行渲染就好了

}
//加
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
StoreProvider.png
2.Store的创建
3.StoreConnector
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
上一篇下一篇

猜你喜欢

热点阅读