likes
comments
collection
share

flutter_redux 的实现原理

作者站长头像
站长
· 阅读数 8

介绍

redux 有三个重要的组成部分,分别是:provider,store,reducer,其中reducer和store负责接收我们自定的action,处理并且返回新的state,然后刷新界面。

而在应对复杂业务场景的情况下,常用的则是:combineReducers和Middleware来处理多业务场景以及复杂的异步处理等。combineReducers可以封装多个reducer,来实现action的细粒度控制,middleware则通过拦截action的方式达到优先于reducer执行的目的。

除此之外,和provider的selector类似的,flutter_redux还提供了distinct控制,来判断是否真的需要刷新视图。

flutter_redux 的实现原理

中间件的实现原理

常需要在其中调用next或者dispatch转发,否则没有意义,一些静默行为除外。

combineReducers和Middleware 实现原理类似,都是通过实现并重写Dart的call函数,是类的实例函数化,在其中判断类型,进而调用入参函数。

  @override
  dynamic call(Store<State> store, dynamic action, NextDispatcher next) {
    if (action is Action) {
      return middleware(store, action, next);
    } else {
      return next(action);
    }
  }
 @override
  State call(State state, dynamic action) {
    if (action is Action) {
      return reducer(state, action);
    }

    return state;
  }

combineReducers

combineReducers的实现较为简单,直接for in 循环遍历并调用。

Reducer<State> combineReducers<State>(Iterable<Reducer<State>> reducers) {
  return (State state, dynamic action) {
    for (final reducer in reducers) {
      state = reducer(state, action);
    }
    return state;
  };
}

Middleware中间件需要在reducer之前调用,可以看下store的dispath实现:


/// _dispatchers 的初始化
List<NextDispatcher> _createDispatchers(
  List<Middleware<State>> middleware,
  NextDispatcher reduceAndNotify,
) {
  /// 将reducer加入到dispatchers中 [reducer]
  final dispatchers = <NextDispatcher>[]..add(reduceAndNotify);

  // Convert each [Middleware] into a [NextDispatcher]
  /// 将中间件加入到dispatchers中 [reducer , middlewares ...]
  for (var nextMiddleware in middleware.reversed) {
    final next = dispatchers.last;

    dispatchers.add(
      (dynamic action) => nextMiddleware(this, action, next),
    );
  }
  /// 反转数组,将中间件放到最前边 [middlewares ... , reducer]
  return dispatchers.reversed.toList();
}

/// store调用dispatch
dynamic dispatch(dynamic action) {
    return _dispatchers[0](action);
}

可以看到每次store调用dispatch的时候,都会从_dispatchers的第一个元素开始调用,而middleware中间件是类似链表的数据结构,next 存储着下一个的中间件调用。

通过源码可以得知,在中间件中,我们可以拦截相同Action的Reducer,并通过next调用reducer,甚至可以通过dispatch进行转发。

distinct 的作用原理

StoreConnector中的distinct

redux是通过流(StreamBuilder)来控制视图刷新的,视图通过调用store.dispatch(action),来触发流,然而redux的流控制并不像bloc一样直接暴露给我们使用,而是自己针对流做了一系列的控制

void _createStream() {
    _stream = widget.store.onChange
        .where(_ignoreChange)
        .map(_mapConverter)
        // Don't use `Stream.distinct` because it cannot capture the initial
        // ViewModel produced by the `converter`.
        .where(_whereDistinct)
        // After each ViewModel is emitted from the Stream, we update the
        // latestValue. Important: This must be done after all other optional
        // transformations, such as ignoreChange.
        .transform(StreamTransformer.fromHandlers(
            handleData: _handleChange, handleError: _handleError));
  }
  • 首先是提供了ignoreChange,可以根据state,来控制是否忽略本次刷新
  • 然后是提供converter返回vm
  • 如果distinct为true的化,比较新旧vm,判断是否需要刷新界面。否则强制刷新。

store中的distinct

在构建store的时候,会发现,store也提供了一个distinct,它的实现作用更为简单粗暴:

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

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

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

在调用reducer之后,直接判断新旧state是否相等,来控制流的发送。

这两个distinct都有控制刷新的作用,区别在于StoreConnector中的distinct可以通过converter来控制判断粒度,来实现变量级的刷新控制,而store中的distinct仅仅适用于函数级。

如何优化?

1.通过distinct的源码实现,不难发现,他们的控制都是通过比较state或者vm来实现的,我们可以通过重载"=="方法来进行更加灵活的刷新控制。

2.redux通过流实现,默认是异步流,可以通过更改syncStream来实现同步流。

转载自:https://juejin.cn/post/6943869301698854925
评论
请登录