flutter_redux(redux状态管理源码详解)原理详解

3 篇文章 0 订阅
1 篇文章 0 订阅

如果要使用redux,那么首先得创建一个Store,顾名思义用来储存数据的类,它的泛型需要自己定义真正保存数据的类放在这里

如下:

 final store = Store<SearchState>(
    searchReducer,
    initialState: SearchInitial(),
    middleware: [
      // The following middleware both achieve the same goal: Load search
      // results from github in response to SearchActions.
      //
      // One is implemented as a normal middleware, the other is implemented as
      // an epic for demonstration purposes.

//        SearchMiddleware(GithubClient()),
      EpicMiddleware<SearchState>(SearchEpic(GithubClient())),
    ],
  );

其中SearchState是用来真正储存信息的类,比如登录的状态,比如主题切换,又比如国家化的方案,方便view树的重新构建,实现逻辑和UI的解耦,其中searchReducer是一个方法,会在你调用store.dispatch方法的时候触发,middleware是一系列方法的组合,会在searchReducer方法之前执行。来看一下Store类的构造方法

 Store(
    this.reducer, {
    State initialState,
    List<Middleware<State>> middleware = const [],
    bool syncStream: false,

    /// If set to true, the Store will not emit onChange events if the new State
    /// that is returned from your [reducer] in response to an Action is equal
    /// to the previous state.
    ///
    /// Under the hood, it will use the `==` method from your State class to
    /// determine whether or not the two States are equal.
    bool distinct: false,
  })
      : _changeController = new StreamController.broadcast(sync: syncStream) {
    _state = initialState;
    _dispatchers = _createDispatchers(
      middleware,
      _createReduceAndNotify(distinct),
    );
  }

构造方法会创建一个StreamController类(用来实现订阅者和发布者的管理类,其实就是用的观察者模式,用来回调seState实现树的部分重新渲染的),其中Middleware就是一个无返回值的传三个参数的方法(typedef在dart中用来声明方法)

typedef void Middleware<State>(
  Store<State> store,
  dynamic action,
  NextDispatcher next,
);
typedef State Reducer<State>(State state, dynamic action);

Reducer也是方法声明, action是dynamic类型的,在操作时由程序员is判断自行使用,Store中的构造函数_createDispatchers方法用来将所有要处理的方法添加到List<NextDispatcher> _dispatchers集合中

 List<NextDispatcher> _createDispatchers(
    List<Middleware<State>> middleware,
    NextDispatcher reduceAndNotify,
  ) {
    final dispatchers = <NextDispatcher>[]..add(reduceAndNotify);

    // Convert each [Middleware] into a [NextDispatcher]
    for (var nextMiddleware in middleware.reversed) {
      final next = dispatchers.last;

      dispatchers.add(
        (dynamic action) => nextMiddleware(this, action, next),
      );
    }

    return dispatchers.reversed.toList();
  }
 NextDispatcher _createReduceAndNotify(bool distinct) {
    return (dynamic action) {
      final state = reducer(_state, action);

      if (distinct && state == _state) return;

      _state = state;
      _changeController.add(state);
    };
  }

_createReduceAndNotify方法就是创建一个NextDispatcherreducer的调用加入其中。

Redux例子中的searchReducer返回的是这么一个类

/// Reducer
final searchReducer = combineReducers<SearchState>([
  TypedReducer<SearchState, SearchLoadingAction>(_onLoad),
  TypedReducer<SearchState, SearchErrorAction>(_onError),
  TypedReducer<SearchState, SearchResultAction>(_onResult),
]);
typedef State Reducer<State>(State state, dynamic action);
Reducer<State> combineReducers<State>(Iterable<Reducer<State>> reducers) {
  return (State state, dynamic action) {
    for (final reducer in reducers) {
      state = reducer(state, action);
    }
    return state;
  };
}

combineReducers方法相当于一个方法的集合包装方法将集合中的所有方法执行一遍,例如这里是3个方法都会被执行到

Reducer是个方法,赋值的时候却是赋值的TypedReducer对象,这就涉及到Dart类中的特殊的用法

class TypedReducer<State, Action> implements ReducerClass<State> {
  final State Function(State state, Action action) reducer;

  TypedReducer(this.reducer);

  @override
  State call(State state, dynamic action) {
    if (action is Action) {
      return reducer(state, action);
    }

    return state;
  }
}

一个类里面有call方法的声明,那么可以把这个类转化为Function方法使用,调用方法时执行的是call方法。

Store声明完了,接下来得用StoreProvider将你的小部件全部包裹起来,以便视图的小部件用来获得Store仓库的属性来刷新子控件的数值

StoreProvider<SearchState>(
      store: store,
      child: MaterialApp(
        title: 'RxDart Github Search',
        theme: ThemeData(
          brightness: Brightness.dark,
          primarySwatch: Colors.grey,
        ),
        home: SearchScreen(),
      ),
    );
  }
class StoreProvider<S> extends InheritedWidget

StoreProvider继承自InheritedWidget,InheritedWidget的用法是用来所有子控件共享数据的,这里共享的就是Store。

最后使用的时候给子部件套上StoreConnector,或者套上StoreBuilder,StoreBuilder内部封装了StoreConnector

 StoreConnector<SearchState, _SearchScreenViewModel>(
      converter: (store) {
        return _SearchScreenViewModel(
          state: store.state,
          onTextChanged: (term) => store.dispatch(SearchAction(term)),
        );
      },
      builder: (BuildContext context, _SearchScreenViewModel vm) {
        return Scaffold(
          body: Flex(direction: Axis.vertical, children: <Widget>[
            Container(
              padding: EdgeInsets.fromLTRB(16.0, 24.0, 16.0, 4.0),
              child: TextField(
                decoration: InputDecoration(
                  border: InputBorder.none,
                  hintText: 'Search Github...',
                ),
                style: TextStyle(
                  fontSize: 36.0,
                  fontFamily: "Hind",
                  decoration: TextDecoration.none,
                ),
                onChanged: vm.onTextChanged,
              ),
            ),
            Expanded(
              child: AnimatedSwitcher(
                duration: Duration(milliseconds: 500),
                child: _buildVisible(vm.state),
              ),
            )
          ]),
StoreConnector的真正实现是_StoreStreamListener的类,声明StoreConnector的时一共使用两个泛型,一个是State(保存view改变的信息),一个是ViewModel(可以看做是业务逻辑)(这里就实现了解耦),converter方法用来将store转化为接下来我们要操作的数据类,类似于Stream的map方法。
class _StoreStreamListener<S, ViewModel> extends StatefulWidget

_StoreStreamListener的rebuildOnChange = true属性默认为true,所以最终构建它的小部件为StreamBuilder

Widget build(BuildContext context) {
    return widget.rebuildOnChange
        ? new StreamBuilder<ViewModel>(
            stream: stream,
            builder: (context, snapshot) => widget.builder(
                  context,
                  snapshot.hasData ? snapshot.data : latestValue,
                ),
          )
        : widget.builder(context, latestValue);
  }
}

StreamBuilder继承与StatefulWidget,所以它可以实现setState状态的改变,那么StreamController的观察者必然在这订阅的,StreamBuilder的State类为_StreamBuilderBaseState,_StreamBuilderBaseState 的initState方法实现了事件的订阅

 void _subscribe() {
    if (widget.stream != null) {
      _subscription = widget.stream.listen((T data) {
        setState(() {
          _summary = widget.afterData(_summary, data);
        });
      }, onError: (Object error) {
        setState(() {
          _summary = widget.afterError(_summary, error);
        });
      }, onDone: () {
        setState(() {
          _summary = widget.afterDone(_summary);
        });
      });
      _summary = widget.afterConnected(_summary);
    }
  }

看到这咱们可以明确StoreProvider作用是负责当前上下文,也就是view树共享Store,而StoreConnector的作用是用来订阅数据的变化,只要数据变化了也就是store.dispatch方法被调用的时候会监听到数据的变化从而触发setState实现view树的重新渲染。

接下来来看一看store.dispatch调用过程

void dispatch(dynamic action) {
    _dispatchers[0](action);
  }

这个方法很简单,从集合中的第一个方法开始调用,也就是先调用middleware的方法call

 call(Store<State> store, dynamic action, NextDispatcher next) {
    if (!_isSubscribed) {
      _epics.stream
          .transform<dynamic>(

              new SwitchMapStreamTransformer<Epic<State>, dynamic>(
                  (epic) => epic(_actions.stream, new EpicStore(store))))
      //订阅store.dispatch
          .listen(store.dispatch);
//添加_epic并执行call
      _epics.add(_epic);

      _isSubscribed = true;
    }
//执行下一个NextDispatcher
    next(action);

    if (supportAsyncGenerators) {
      // Future.delayed is an ugly hack to support async* functions.
      //
      // See: https://github.com/dart-lang/sdk/issues/33818
      new Future.delayed(Duration.zero, () {
        _actions.add(action);
      });
    } else {
      _actions.add(action);
    }
  }

再执行searchReducer方法

 NextDispatcher _createReduceAndNotify(bool distinct) {
    return (dynamic action) {
      final state = reducer(_state, action);

      if (distinct && state == _state) return;

      _state = state;
      //发布一个事件
      _changeController.add(state);
    };
  }

执行完searchReducer方法之后,判断state有没有变化,如果变化了就会通过StreamController发布事件,通知StoreConnector调用setState从而重新渲染。

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值