概览

Flutter状态管理 - 图3

声明式编程思维

Flutter状态管理 - 图4

Flutter状态管理 - 图5

  1. // Imperative style
  2. b.setColor(red)
  3. b.clearChildren()
  4. ViewC c3 = new ViewC(...)
  5. b.add(c3)
  1. // Declarative style
  2. return ViewB(
  3. color: red,
  4. child: ViewC(...),
  5. )

直观认识State

image.png

状态的分类

  • 短暂状态 ephemeral state (əˈfem(ə)rəl)
  • 应用状态 app state

image.png

ShoppingCartDemo (使用InheritedWidget)

点击查看【bilibili】

Flutter状态管理 - 图8

image.png

Redux

image.png
image.png
image.png
image.png

image.png

  1. import 'dart:async';
  2. /// Defines an application's state change
  3. ///
  4. /// Implement this typedef to modify your app state in response to a given
  5. /// action.
  6. ///
  7. /// ### Example
  8. ///
  9. /// int counterReducer(int state, action) {
  10. /// switch (action) {
  11. /// case 'INCREMENT':
  12. /// return state + 1;
  13. /// case 'DECREMENT':
  14. /// return state - 1;
  15. /// default:
  16. /// return state;
  17. /// }
  18. /// }
  19. ///
  20. /// final store = new Store<int>(counterReducer);
  21. typedef Reducer<State> = State Function(State state, dynamic action);
  22. /// Defines a [Reducer] using a class interface.
  23. ///
  24. /// Implement this class to modify your app state in response to a given action.
  25. ///
  26. /// For some use cases, a class may be preferred to a function. In these
  27. /// instances, a ReducerClass can be used.
  28. ///
  29. /// ### Example
  30. ///
  31. /// class CounterReducer extends ReducerClass<int> {
  32. /// int call(int state, action) {
  33. /// switch (action) {
  34. /// case 'INCREMENT':
  35. /// return state + 1;
  36. /// case 'DECREMENT':
  37. /// return state - 1;
  38. /// default:
  39. /// return state;
  40. /// }
  41. /// }
  42. /// }
  43. ///
  44. /// final store = new Store<int>(new CounterReducer());
  45. abstract class ReducerClass<State> {
  46. /// The [Reducer] function that converts the current state and action into a
  47. /// new state
  48. State call(State state, dynamic action);
  49. }
  50. /// A function that intercepts actions and potentially transform actions before
  51. /// they reach the reducer.
  52. ///
  53. /// Middleware intercept actions before they reach the reducer. This gives them
  54. /// the ability to produce side-effects or modify the passed in action before
  55. /// they reach the reducer.
  56. ///
  57. /// ### Example
  58. ///
  59. /// loggingMiddleware(Store<int> store, action, NextDispatcher next) {
  60. /// print('${new DateTime.now()}: $action');
  61. ///
  62. /// next(action);
  63. /// }
  64. ///
  65. /// // Create your store with the loggingMiddleware
  66. /// final store = new Store<int>(
  67. /// counterReducer,
  68. /// middleware: [loggingMiddleware],
  69. /// );
  70. typedef Middleware<State> = dynamic Function(
  71. Store<State> store,
  72. dynamic action,
  73. NextDispatcher next,
  74. );
  75. /// Defines a [Middleware] using a Class interface.
  76. ///
  77. /// Middleware intercept actions before they reach the reducer. This gives them
  78. /// the ability to produce side-effects or modify the passed in action before
  79. /// they reach the reducer.
  80. ///
  81. /// For some use cases, a class may be preferred to a function. In these
  82. /// instances, a MiddlewareClass can be used.
  83. ///
  84. /// ### Example
  85. /// class LoggingMiddleware extends MiddlewareClass<int> {
  86. /// call(Store<int> store, action, NextDispatcher next) {
  87. /// print('${new DateTime.now()}: $action');
  88. ///
  89. /// next(action);
  90. /// }
  91. /// }
  92. ///
  93. /// // Create your store with the loggingMiddleware
  94. /// final store = new Store<int>(
  95. /// counterReducer,
  96. /// middleware: [new LoggingMiddleware()],
  97. /// );
  98. abstract class MiddlewareClass<State> {
  99. /// A [Middleware] function that intercepts a dispatched action
  100. dynamic call(Store<State> store, dynamic action, NextDispatcher next);
  101. }
  102. /// The contract between one piece of middleware and the next in the chain. Use
  103. /// it to send the current action in your [Middleware] to the next piece of
  104. /// [Middleware] in the chain.
  105. ///
  106. /// Middleware can optionally pass the original action or a modified action to
  107. /// the next piece of middleware, or never call the next piece of middleware at
  108. /// all.
  109. typedef NextDispatcher = dynamic Function(dynamic action);
  110. /// Creates a Redux store that holds the app state tree.
  111. ///
  112. /// The only way to change the state tree in the store is to [dispatch] an
  113. /// action. the action will then be intercepted by any provided [Middleware].
  114. /// After running through the middleware, the action will be sent to the given
  115. /// [Reducer] to update the state tree.
  116. ///
  117. /// To access the state tree, call the [state] getter or listen to the
  118. /// [onChange] stream.
  119. ///
  120. /// ### Basic Example
  121. ///
  122. /// // Create a reducer
  123. /// final increment = 'INCREMENT';
  124. /// final decrement = 'DECREMENT';
  125. ///
  126. /// int counterReducer(int state, action) {
  127. /// switch (action) {
  128. /// case increment:
  129. /// return state + 1;
  130. /// case decrement:
  131. /// return state - 1;
  132. /// default:
  133. /// return state;
  134. /// }
  135. /// }
  136. ///
  137. /// // Create the store
  138. /// final store = new Store<int>(counterReducer, initialState: 0);
  139. ///
  140. /// // Print the Store's state.
  141. /// print(store.state); // prints "0"
  142. ///
  143. /// // Dispatch an action. This will be sent to the reducer to update the
  144. /// // state.
  145. /// store.dispatch(increment);
  146. ///
  147. /// // Print the updated state. As an alternative, you can use the
  148. /// // `store.onChange.listen` to respond to all state change events.
  149. /// print(store.state); // prints "1"
  150. class Store<State> {
  151. /// The [Reducer] for your Store. Allows you to get the current reducer or
  152. /// replace it with a new one if need be.
  153. Reducer<State> reducer;
  154. final StreamController<State> _changeController;
  155. State _state;
  156. List<NextDispatcher> _dispatchers;
  157. /// Creates an instance of a Redux Store.
  158. ///
  159. /// The [reducer] argument specifies how the state should be changed in
  160. /// response to dispatched actions.
  161. ///
  162. /// The optional [initialState] argument defines the State of the store when
  163. /// the Store is first created.
  164. ///
  165. /// The optional [middleware] argument takes a list of [Middleware] functions
  166. /// or [MiddlewareClass]. See the [Middleware] documentation for information
  167. /// on how they are used.
  168. ///
  169. /// The [syncStream] argument allows you to use a synchronous
  170. /// [StreamController] instead of an async `StreamController` under the hood.
  171. /// By default, the Stream is async.
  172. Store(
  173. this.reducer, {
  174. State initialState,
  175. List<Middleware<State>> middleware = const [],
  176. bool syncStream = false,
  177. /// If set to true, the Store will not emit onChange events if the new State
  178. /// that is returned from your [reducer] in response to an Action is equal
  179. /// to the previous state.
  180. ///
  181. /// Under the hood, it will use the `==` method from your State class to
  182. /// determine whether or not the two States are equal.
  183. bool distinct = false,
  184. }) : _changeController = StreamController.broadcast(sync: syncStream) {
  185. _state = initialState;
  186. _dispatchers = _createDispatchers(
  187. middleware,
  188. _createReduceAndNotify(distinct),
  189. );
  190. }
  191. /// Returns the current state of the app
  192. State get state => _state;
  193. /// A stream that emits the current state when it changes.
  194. ///
  195. /// ### Example
  196. ///
  197. /// // First, create the Store
  198. /// final store = new Store<int>(counterReducer, 0);
  199. ///
  200. /// // Next, listen to the Store's onChange stream, and print the latest
  201. /// // state to your console whenever the reducer produces a new State.
  202. /// //
  203. /// // We'll store the StreamSubscription as a variable so we can stop
  204. /// // listening later.
  205. /// final subscription = store.onChange.listen(print);
  206. ///
  207. /// // Dispatch some actions, and see the printing magic!
  208. /// store.dispatch("INCREMENT"); // prints 1
  209. /// store.dispatch("INCREMENT"); // prints 2
  210. /// store.dispatch("DECREMENT"); // prints 1
  211. ///
  212. /// // When you want to stop printing the state to the console, simply
  213. /// `cancel` your `subscription`.
  214. /// subscription.cancel();
  215. Stream<State> get onChange => _changeController.stream;
  216. // Creates the base [NextDispatcher].
  217. //
  218. // The base NextDispatcher will be called after all other middleware provided
  219. // by the user have been run. Its job is simple: Run the current state through
  220. // the reducer, save the result, and notify any subscribers.
  221. NextDispatcher _createReduceAndNotify(bool distinct) {
  222. return (dynamic action) {
  223. final state = reducer(_state, action);
  224. if (distinct && state == _state) return;
  225. _state = state;
  226. _changeController.add(state);
  227. };
  228. }
  229. List<NextDispatcher> _createDispatchers(
  230. List<Middleware<State>> middleware,
  231. NextDispatcher reduceAndNotify,
  232. ) {
  233. final dispatchers = <NextDispatcher>[]..add(reduceAndNotify);
  234. // Convert each [Middleware] into a [NextDispatcher]
  235. for (var nextMiddleware in middleware.reversed) {
  236. final next = dispatchers.last;
  237. dispatchers.add(
  238. (dynamic action) => nextMiddleware(this, action, next),
  239. );
  240. }
  241. return dispatchers.reversed.toList();
  242. }
  243. /// Runs the action through all provided [Middleware], then applies an action
  244. /// to the state using the given [Reducer]. Please note: [Middleware] can
  245. /// intercept actions, and can modify actions or stop them from passing
  246. /// through to the reducer.
  247. dynamic dispatch(dynamic action) {
  248. return _dispatchers[0](action);
  249. }
  250. /// Closes down the Store so it will no longer be operational. Only use this
  251. /// if you want to destroy the Store while your app is running. Do not use
  252. /// this method as a way to stop listening to [onChange] state changes. For
  253. /// that purpose, view the [onChange] documentation.
  254. Future teardown() async {
  255. _state = null;
  256. return _changeController.close();
  257. }
  258. }

更多阅读