@@ -10,13 +10,25 @@ Inspired by [redux][redux_git]
10
10
11
11
Built using [ built_value] [ built_value_git ]
12
12
13
- ## Framework bindings & examples
13
+ ## Framework bindings
14
14
15
15
[ flutter] [ flutter ]
16
16
17
- [ react-dart ] [ react-dart ]
17
+ ## examples
18
18
19
- [ angular2] [ angular2 ]
19
+ [ nested state & actions] [ nesting ]
20
+
21
+ [ building reducers for built collections] [ collection_reducers ]
22
+
23
+ [ inheritence in state & actions] [ inheritence ]
24
+
25
+ ## libraries
26
+
27
+ [ thunk] [ built_redux_thunk ]
28
+
29
+ [ rx] [ built_redux_rx ]
30
+
31
+ [ repatch] [ built_redux_repatch ]
20
32
21
33
## Using it in your project
22
34
@@ -29,10 +41,9 @@ Built using [built_value][built_value_git]
29
41
> gain familiarity with it by reading [ this blog post] [ built_value_blog ] .
30
42
31
43
1 . Add the ` built_redux ` package as a dependency in your ` pubspec.yaml ` .
32
-
33
44
``` yaml
34
45
dependencies :
35
- built_redux : " ^6 .0.0"
46
+ built_redux : " ^7 .0.0"
36
47
` ` `
37
48
38
49
2. Create a script to run generators for generating built_values and built_redux action classes.
@@ -44,51 +55,52 @@ Built using [built_value][built_value_git]
44
55
import 'package:source_gen/source_gen.dart';
45
56
import 'package:built_redux/generator.dart';
46
57
47
- /// Build the generated files in the built_value chat example.
48
58
Future main(List<String> args) async {
49
59
await build([
50
60
new BuildAction(
51
61
new PartBuilder([
52
62
new BuiltValueGenerator(),
53
63
new BuiltReduxGenerator(),
54
64
]),
65
+ // your lib name here
55
66
' built_redux' ,
56
- inputs : const ['test/unit/test_counter.dart'])
67
+ // tweak the files that invoke the generator here
68
+ inputs : const ['lib/**/*.dart'])
57
69
], deleteFilesByDefault : true);
58
70
}
59
71
```
60
72
61
- 3 . Run the build script from the command line to generate your built_values and built_redux action classes
62
- ``` dart tool/build.dart ```
73
+ 3 . Run the build script from the command line to generate your built_values and built_redux action classes by running ` dart [build script name].dart `
63
74
64
- ### Writing a built_redux store
75
+ ### Implementing a built_redux store
65
76
66
77
``` dart
67
78
import 'package:built_value/built_value.dart';
68
79
import 'package:built_redux/built_redux.dart';
69
80
70
- // This is a an implementation of ReduxActions. Actions are what middleware and ui
71
- // components invoke a change to the redux store's state. By extending ReduxActions
72
- // the built_redux generator will generate the required boilerplate to create
73
- // each action and an ActionNames class.
74
- abstract class CounterActions extends ReduxActions {
75
- ActionDispatcher<int> increment;
76
- ActionDispatcher<int> decrement;
77
-
78
- // factory to create on instance of the generated implementation of CounterActions
79
- CounterActions._();
80
- factory CounterActions() => new _$CounterActions();
81
- }
81
+ // This is a an implementation of ReduxActions. Actions are what middleware and ui
82
+ // components invoke a change to the redux store's state. By extending ReduxActions
83
+ // the built_redux generator will generate the required boilerplate to create
84
+ // each action and an ActionNames class. The ActionNames class is used to register
85
+ // reducers
86
+ abstract class CounterActions extends ReduxActions {
87
+ ActionDispatcher<int> get increment;
88
+ ActionDispatcher<int> get decrement;
89
+
90
+ // factory to create on instance of the generated implementation of CounterActions
91
+ CounterActions._();
92
+ factory CounterActions() => new _$CounterActions();
93
+ }
82
94
83
- // This is a built value. It is an immutable model that implements the Built interface.
84
- // All of the state in your redux store is contained in a single built value model.
85
- abstract class Counter implements Built<Counter, CounterBuilder> {
86
- /// [count] value of the counter
87
- int get count;
95
+ // This is a built value. It is an immutable model that implements the Built interface.
96
+ // All of the state in your redux store is contained in a single built value model.
97
+ abstract class Counter implements Built<Counter, CounterBuilder> {
98
+ /// [count] value of the counter
99
+ int get count;
88
100
89
- // Built value constructor. The factory is returning the default state
90
- Counter._();
91
- factory Counter() => new _$Counter._(count: 1);
101
+ // Built value constructor. The factory is returning the default state
102
+ Counter._();
103
+ factory Counter() => new _$Counter._(count: 1);
92
104
}
93
105
94
106
@@ -101,19 +113,19 @@ increment(Counter state, Action<int> action, CounterBuilder builder) =>
101
113
decrement(Counter state, Action<int> action, CounterBuilder builder) =>
102
114
builder.count = state.count - action.payload;
103
115
104
- // This is a reducer builder. Use of ReducerBuilder is not required, however it
105
- // is strongly recommended as it gives you static type checking to make sure
106
- // the payload for action name provided is the same as the expected payload
107
- // for the action provided to your reducer. Calling .build() returns a reducer function
108
- // that can be passed to the store's constructor.
109
- var reducer = ( new ReducerBuilder<Counter, CounterBuilder>()
110
- ..add(CounterActionsNames.increment, increment)
111
- ..add(CounterActionsNames.decrement, decrement)).build( );
116
+ // This is a reducer builder. Use of ReducerBuilder is not required, however it
117
+ // is strongly recommended as it gives you static type checking to make sure
118
+ // the payload for action name provided is the same as the expected payload
119
+ // for the action provided to your reducer. Calling .build() returns a reducer function
120
+ // that can be passed to the store's constructor.
121
+ var reducerBuilder = new ReducerBuilder<Counter, CounterBuilder>()
122
+ ..add(CounterActionsNames.increment, increment)
123
+ ..add(CounterActionsNames.decrement, decrement);
112
124
113
- // Create a Redux store holding the state of your app.
125
+ // Create a redux store holding the state of your app.
114
126
// Its API contains three getters: stream, state, and actions.
115
127
var store = new Store<Counter, CounterBuilder, CounterActions>(
116
- reducer,
128
+ reducerBuilder.build(), // build returns a reducer function
117
129
new Counter(),
118
130
new CounterActions(),
119
131
);
@@ -130,121 +142,32 @@ store.actions.decrement(1);
130
142
// 2
131
143
```
132
144
133
- ### Nested Reducers
134
-
135
- Nested reducers can be built to handle rebuilding built values that are
136
- nested within the state tree. This is nice for organization and scoping actions to a specific piece of your application's state.
137
-
138
- ``` dart
139
- // the state model
140
- abstract class BaseCounter implements Built<BaseCounter, BaseCounterBuilder> {
141
- int get count;
142
-
143
- // Also a built_value
144
- NestedCounter get nestedCounter;
145
-
146
- // Built value constructor. The factory is returning the default state
147
- BaseCounter._();
148
- factory BaseCounter() => new _$BaseCounter._(
149
- count: 1,
150
- nestedCounter: new NestedCounter(),
151
- );
152
- }
153
-
154
- // the nested model
155
- abstract class NestedCounter implements Built<NestedCounter, NestedCounterBuilder> {
156
- int get count;
157
-
158
- // Built value constructor. The factory is returning the default state
159
- NestedCounter._();
160
- factory NestedCounter() => new _$NestedCounter._(
161
- count: 1,
162
- );
163
- }
164
-
165
- // create a nested reducer builder
166
- final nestedReducer = new NestedReducerBuilder<BaseCounter, BaseCounterBuilder,
167
- NestedCounter, NestedCounterBuilder>(
168
- (state) => state.nestedCounter, // maps the app state to the nested state
169
- (builder) => builder.nestedCounter, // maps the app builder to the nested builder
170
- )..add(NestedCounterActionsNames.increment, _nestedIncrement);
171
-
172
- // actions registered only rebuild the nested state
173
- // notice the state and builder types are of NestedCounter and NestedCounterBuilder
174
- _nestedIncrement(NestedCounter state, Action<int> action, NestedCounterBuilder builder) =>
175
- builder.count = state.count + action.payload;
176
-
177
- // now use ReducerBuilder.combineNested to add it to your main reducer
178
- var reducer = (new ReducerBuilder<Counter, CounterBuilder>()
179
- ..add(CounterActionsNames.increment, increment)
180
- ..add(CounterActionsNames.decrement, decrement)
181
- ..combineNested(nestedReducer)).build();
182
-
183
- ```
184
-
185
- Nested actions can also be used to help organize actions for nested reducers. First define your actions:
186
-
187
- ``` dart
188
- abstract class NestedActions extends ReduxActions {
189
- ActionDispatcher<int> increment;
190
- ActionDispatcher<int> decrement;
191
-
192
- // factory to create on instance of the generated implementation of NestedActions
193
- NestedActions._();
194
- factory NestedActions() => new _$NestedActions();
195
- }
196
- ```
197
-
198
- Then add them to your main action class like so:
199
-
200
- ``` dart
201
- abstract class CounterActions extends ReduxActions {
202
- ActionDispatcher<int> increment;
203
- ActionDispatcher<int> decrement;
204
-
205
- NestedActions nestedActions;
206
-
207
- // factory to create on instance of the generated implementation of CounterActions
208
- CounterActions._();
209
- factory CounterActions() => new _$CounterActions();
210
- }
211
- ```
212
-
213
- Check the usage:
214
-
215
- ``` dart
216
- // only print the nested counter's count
217
- store.stream.listen((_) => print(store.state.nestedCounter.count));
218
-
219
- // The only way to mutate the internal state is to dispatch an action.
220
- store.actions.nestedActions.increment(1);
221
- // 1
222
- store.actions.increment(2);
223
- // 1
224
- ```
225
-
226
145
### Writing middleware
227
146
228
147
``` dart
229
- // Define specific actions to be handled by this middleware
230
- // A middleware can also listen to and perform side effects on any actions defined elsewhere
148
+ // Define specific actions to be handled by this middleware.
149
+ // A middleware can also listen to and perform side effects on any actions defined
150
+ // elsewhere. It is possible that a middleware will not need any of its own actions
151
+ // defined.
231
152
abstract class DoubleAction extends ReduxActions {
232
- ActionDispatcher<int> increment;
153
+ ActionDispatcher<int> get increment;
233
154
234
155
DoubleAction._();
235
156
factory DoubleAction() => new _$DoubleAction();
236
157
}
237
158
238
- // This is a middleware builder. Use of MiddlewareBuilder is not required, however
239
- // just like ReducerBuilder it is strongly recommended as it gives you static type checking to make sure
240
- // the payload for action name provided is the same as the expected payload
241
- // for the action provided to your reducer. It will also call next(action) for you
242
- // if an action not handled by this middleware is received. Calling .build() returns the
243
- // middleware function that can be passed to your store at instantiation.
244
- var doubleMiddleware = (new MiddlewareBuilder<Counter, CounterBuilder, CounterActions>()
245
- ..add(DoubleActionNames.increment, _doubleIt)).build();
246
-
247
- _doubleIt(MiddlewareApi<Counter, CounterBuilder, CounterActions> api, ActionHandler next, Action<int> action) {
159
+ // This is a middleware builder. Use of MiddlewareBuilder is not required, however
160
+ // just like ReducerBuilder it is strongly recommended as it gives you static type checking to make sure
161
+ // the payload for action name provided is the same as the expected payload
162
+ // for the action provided to your reducer. It will also call next(action) for you
163
+ // if an action not handled by this middleware is received. Calling .build() returns the
164
+ // middleware function that can be passed to your store at instantiation.
165
+ var doubleMiddleware = (new MiddlewareBuilder<Counter, CounterBuilder, CounterActions>()
166
+ ..add(DoubleActionNames.increment, _doubleIt)).build();
167
+
168
+ void _doubleIt(MiddlewareApi<Counter, CounterBuilder, CounterActions> api, ActionHandler next, Action<int> action) {
169
+ // doubles the action payload and kicks off a new action to increment the
170
+ // store by that amount.
248
171
api.actions.increment(action.payload * 2);
249
172
}
250
173
```
@@ -301,6 +224,27 @@ NextActionHandler loggingMiddleware(MiddlewareApi<Counter, CounterBuilder, Count
301
224
};
302
225
```
303
226
227
+ ### Observing state
228
+
229
+ The store's stream fires with a payload of type StoreChange. This is an object
230
+ that contains the action, the previous state, and the next state. If you would
231
+ like to set up a stream thats payload is simply the next state, use store.nexState
232
+
233
+ ``` dart
234
+
235
+ print(store.state.count);
236
+ // 1
237
+
238
+ store.nextState.listen(print);
239
+
240
+ store.actions.increment(1);
241
+ // 2
242
+
243
+ store.actions.increment(3);
244
+ // 5
245
+
246
+ ```
247
+
304
248
### Observing substate
305
249
306
250
Streams can easily be accessed to observe any piece of your state tree by passing a mapper the store's
@@ -320,6 +264,25 @@ store.actions.nestedCounter.increment(2);
320
264
321
265
```
322
266
267
+ In the case of substate streams, the payload is of type SubStateChange. This is an object the previous state, and the next state. If you would
268
+ like to set up a stream thats payload is simply the next subState, use store.nexSubstate
269
+
270
+ ``` dart
271
+
272
+ print(store.state.count);
273
+ // 1
274
+
275
+ store.nextSubstate((BaseCounter state) => state.count)
276
+ .listen(print);
277
+
278
+ store.actions.increment(1);
279
+ // 2
280
+
281
+ store.actions.increment(3);
282
+ // 5
283
+
284
+ ```
285
+
323
286
[ built_value_blog ] : https://medium.com/dartlang/darts-built-value-for-immutable-object-models-83e2497922d4
324
287
325
288
[ built_value_git ] : https://github.com/google/built_value.dart/
@@ -328,10 +291,18 @@ store.actions.nestedCounter.increment(2);
328
291
329
292
[ redux_docs ] : http://redux.js.org/
330
293
331
- [ react-dart ] : https://github.com/davidmarne/react_built_redux
332
-
333
294
[ flutter ] : https://github.com/davidmarne/flutter_built_redux
334
295
335
- [ angular2 ] : https://github.com/davidmarne/angular_built_redux
296
+ [ built_redux_thunk ] : https://github.com/davidmarne/built_redux_thunk
297
+
298
+ [ built_redux_rx ] : https://github.com/davidmarne/built_redux_rx
299
+
300
+ [ built_redux_repatch ] : https://github.com/davidmarne/built_redux_repatch
336
301
337
302
[ flutter_built_redux ] : https://github.com/davidmarne/flutter_built_redux
303
+
304
+ [ nesting ] : test/unit/nested_models.dart
305
+
306
+ [ collection_reducers ] : test/unit/collection_models.dart
307
+
308
+ [ inheritence ] : test/unit/inheritance_test_models.dart
0 commit comments