Skip to content

Commit 5719469

Browse files
authored
Merge pull request #39 from davidmarne/inheritance
7.1.0
2 parents aeddcd2 + 82130f5 commit 5719469

25 files changed

+2030
-761
lines changed

Diff for: .travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ script:
55
- dart tool/build.dart
66
- pub run dart_dev format --check
77
- pub run dart_dev analyze
8-
- pub run dart_dev test
8+
- pub run dart_dev test -p vm
99
- pub run dart_dev coverage --no-html
1010
- bash <(curl -s https://codecov.io/bash) -f coverage/coverage.lcov

Diff for: README.md

+120-149
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,25 @@ Inspired by [redux][redux_git]
1010

1111
Built using [built_value][built_value_git]
1212

13-
## Framework bindings & examples
13+
## Framework bindings
1414

1515
[flutter][flutter]
1616

17-
[react-dart][react-dart]
17+
## examples
1818

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]
2032

2133
## Using it in your project
2234

@@ -29,10 +41,9 @@ Built using [built_value][built_value_git]
2941
> gain familiarity with it by reading [this blog post][built_value_blog].
3042
3143
1. Add the `built_redux` package as a dependency in your `pubspec.yaml`.
32-
3344
```yaml
3445
dependencies:
35-
built_redux: "^6.0.0"
46+
built_redux: "^7.0.0"
3647
```
3748
3849
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]
4455
import 'package:source_gen/source_gen.dart';
4556
import 'package:built_redux/generator.dart';
4657

47-
/// Build the generated files in the built_value chat example.
4858
Future main(List<String> args) async {
4959
await build([
5060
new BuildAction(
5161
new PartBuilder([
5262
new BuiltValueGenerator(),
5363
new BuiltReduxGenerator(),
5464
]),
65+
// your lib name here
5566
'built_redux',
56-
inputs: const ['test/unit/test_counter.dart'])
67+
// tweak the files that invoke the generator here
68+
inputs: const ['lib/**/*.dart'])
5769
], deleteFilesByDefault: true);
5870
}
5971
```
6072

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`
6374

64-
### Writing a built_redux store
75+
### Implementing a built_redux store
6576

6677
```dart
6778
import 'package:built_value/built_value.dart';
6879
import 'package:built_redux/built_redux.dart';
6980
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+
}
8294
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;
88100
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);
92104
}
93105
94106
@@ -101,19 +113,19 @@ increment(Counter state, Action<int> action, CounterBuilder builder) =>
101113
decrement(Counter state, Action<int> action, CounterBuilder builder) =>
102114
builder.count = state.count - action.payload;
103115
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);
112124
113-
// Create a Redux store holding the state of your app.
125+
// Create a redux store holding the state of your app.
114126
// Its API contains three getters: stream, state, and actions.
115127
var store = new Store<Counter, CounterBuilder, CounterActions>(
116-
reducer,
128+
reducerBuilder.build(), // build returns a reducer function
117129
new Counter(),
118130
new CounterActions(),
119131
);
@@ -130,121 +142,32 @@ store.actions.decrement(1);
130142
// 2
131143
```
132144

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-
226145
### Writing middleware
227146

228147
```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.
231152
abstract class DoubleAction extends ReduxActions {
232-
ActionDispatcher<int> increment;
153+
ActionDispatcher<int> get increment;
233154
234155
DoubleAction._();
235156
factory DoubleAction() => new _$DoubleAction();
236157
}
237158
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.
248171
api.actions.increment(action.payload * 2);
249172
}
250173
```
@@ -301,6 +224,27 @@ NextActionHandler loggingMiddleware(MiddlewareApi<Counter, CounterBuilder, Count
301224
};
302225
```
303226

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+
304248
### Observing substate
305249

306250
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);
320264
321265
```
322266

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+
323286
[built_value_blog]: https://medium.com/dartlang/darts-built-value-for-immutable-object-models-83e2497922d4
324287

325288
[built_value_git]: https://github.com/google/built_value.dart/
@@ -328,10 +291,18 @@ store.actions.nestedCounter.increment(2);
328291

329292
[redux_docs]: http://redux.js.org/
330293

331-
[react-dart]: https://github.com/davidmarne/react_built_redux
332-
333294
[flutter]: https://github.com/davidmarne/flutter_built_redux
334295

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
336301

337302
[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

Diff for: analysis_options.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
analyzer:
22
strong-mode: true
3+
implicit-dynamic: false
4+
implicit-casts: false

0 commit comments

Comments
 (0)