Skip to content

Commit 649f34a

Browse files
authored
Merge pull request #8 from hoc081098/null_safety
null_safety!
2 parents 71e2036 + 2a5228f commit 649f34a

15 files changed

+3714
-142
lines changed

.github/workflows/dart.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313

1414
container:
15-
image: google/dart:latest
15+
image: google/dart:2.12-beta
1616

1717
steps:
1818
- uses: actions/checkout@v2

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
language: dart
22
dart:
3-
- stable
43
- dev
4+
- beta
55
script:
66
- dartanalyzer --fatal-infos --fatal-warnings ./lib ./test
77
- dartfmt -n ./lib --set-exit-if-changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 2.2.0-nullsafety.1 - Nov 30, 2020
2+
- Fixed: support nullable action.
3+
4+
## 2.2.0-nullsafety.0 - Nov 28, 2020
5+
- Migrate this package to null safety.
6+
- Sdk constraints: `>=2.12.0-0 <3.0.0` based on beta release guidelines.
7+
18
## 2.1.1 - Oct 30, 2020
29

310
- Add `RxReduxStore.dispatchMany(Stream<A>)`: Dispatch a `Stream` of actions to store.

example/counter.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ void main() async {
3838

3939
store.stateStream.listen(print);
4040

41-
await Stream.periodic(const Duration(seconds: 1), (i) => i + 1)
41+
Stream.periodic(const Duration(milliseconds: 500), (i) => i + 1)
4242
.take(10)
4343
.map((i) => i.isEven ? Increment(i) : Decrement(i))
44-
.forEach(store.dispatch);
44+
.dispatchTo(store);
4545

46-
await Future(() {});
46+
await Future<void>.delayed(const Duration(seconds: 6));
4747
await store.dispose();
4848
}

lib/rx_redux.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ export 'src/logger.dart';
44
export 'src/reducer.dart';
55
export 'src/reducer_exception.dart';
66
export 'src/redux_store_stream_transformer.dart';
7+
export 'src/selectors.dart';
78
export 'src/side_effect.dart';
89
export 'src/store.dart';

lib/src/reducer.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,4 @@
77
/// * Param [currentState] [S] The type of the state
88
/// * Param [newAction] [A] The type of the Actions
99
///
10-
1110
typedef Reducer<A, S> = S Function(S currentState, A newAction);

lib/src/reducer_exception.dart

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import 'package:meta/meta.dart';
2-
31
/// Exception thrown by reducer
42
class ReducerException<A, S> implements Exception {
53
/// Action passed into reducer
@@ -16,10 +14,10 @@ class ReducerException<A, S> implements Exception {
1614

1715
/// Construct a [ReducerException]
1816
const ReducerException({
19-
@required this.action,
20-
@required this.state,
21-
@required this.error,
22-
this.stackTrace,
17+
required this.action,
18+
required this.state,
19+
required this.error,
20+
required this.stackTrace,
2321
});
2422

2523
@override

lib/src/redux_store_stream_transformer.dart

Lines changed: 41 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import 'dart:async';
22

3-
import 'package:meta/meta.dart';
4-
53
import 'logger.dart';
64
import 'reducer.dart';
75
import 'reducer_exception.dart';
@@ -34,10 +32,10 @@ extension ReduxStoreExt<Action> on Stream<Action> {
3432
/// * Param [State] The type of the State
3533
/// * Param [Action] The type of the Actions
3634
Stream<State> reduxStore<State>({
37-
@required State Function() initialStateSupplier,
38-
@required Iterable<SideEffect<Action, State>> sideEffects,
39-
@required Reducer<Action, State> reducer,
40-
RxReduxLogger logger,
35+
required State Function() initialStateSupplier,
36+
required Iterable<SideEffect<Action, State>> sideEffects,
37+
required Reducer<Action, State> reducer,
38+
RxReduxLogger? logger,
4139
}) =>
4240
transform(
4341
ReduxStoreStreamTransformer(
@@ -66,7 +64,7 @@ class ReduxStoreStreamTransformer<A, S> extends StreamTransformerBase<A, S> {
6664
final S Function() _initialStateSupplier;
6765
final Iterable<SideEffect<A, S>> _sideEffects;
6866
final Reducer<A, S> _reducer;
69-
final RxReduxLogger _logger;
67+
final RxReduxLogger? _logger;
7068

7169
/// * Param [initialStateSupplier] A function that computes the initial state. The computation is
7270
/// * done lazily once an observer subscribes. The computed initial state will be emitted directly
@@ -77,26 +75,20 @@ class ReduxStoreStreamTransformer<A, S> extends StreamTransformerBase<A, S> {
7775
/// * Param [S] The type of the State
7876
/// * Param [A] The type of the Actions
7977
ReduxStoreStreamTransformer({
80-
@required S Function() initialStateSupplier,
81-
@required Iterable<SideEffect<A, S>> sideEffects,
82-
@required Reducer<A, S> reducer,
83-
RxReduxLogger logger,
84-
}) : assert(initialStateSupplier != null,
85-
'initialStateSupplier cannot be null'),
86-
assert(sideEffects != null, 'sideEffects cannot be null'),
87-
assert(sideEffects.every((sideEffect) => sideEffect != null),
88-
'All sideEffects must be not null'),
89-
assert(reducer != null, 'reducer cannot be null'),
90-
_initialStateSupplier = initialStateSupplier,
78+
required S Function() initialStateSupplier,
79+
required Iterable<SideEffect<A, S>> sideEffects,
80+
required Reducer<A, S> reducer,
81+
RxReduxLogger? logger,
82+
}) : _initialStateSupplier = initialStateSupplier,
9183
_sideEffects = sideEffects,
9284
_reducer = reducer,
9385
_logger = logger;
9486

9587
@override
9688
Stream<S> bind(Stream<A> stream) {
97-
StreamController<S> controller;
98-
List<StreamSubscription<dynamic>> subscriptions;
99-
StreamController<WrapperAction<A>> actionController;
89+
late StreamController<S> controller;
90+
List<StreamSubscription<Object?>>? subscriptions;
91+
StreamController<WrapperAction>? _actionController;
10092

10193
void onListen() {
10294
S state;
@@ -109,20 +101,20 @@ class ReduxStoreStreamTransformer<A, S> extends StreamTransformerBase<A, S> {
109101
return;
110102
}
111103

112-
void onDataActually(WrapperAction<A> wrapper) {
113-
final action = wrapper.action;
104+
void onDataActually(WrapperAction wrapper) {
114105
final type = wrapper.type;
115106
final currentState = state;
116107

117108
// add initial state
118-
if (identical(type, ActionType.initial)) {
109+
if (identical(wrapper, WrapperAction.initial)) {
119110
final message = '\n'
120111
' ⟶ Action : $type\n'
121112
' ⟹ Current state: $currentState';
122113
_logger?.call(message);
123114
return controller.add(currentState);
124115
}
125116

117+
final action = wrapper.action<A>();
126118
try {
127119
final newState = _reducer(currentState, action);
128120
controller.add(newState);
@@ -151,35 +143,39 @@ class ReduxStoreStreamTransformer<A, S> extends StreamTransformerBase<A, S> {
151143
}
152144
}
153145

154-
actionController = StreamController<WrapperAction<A>>.broadcast();
146+
final actionController =
147+
_actionController = StreamController<WrapperAction>.broadcast();
155148

156149
// Call reducer on each action.
157150
final subscriptionActionController =
158151
actionController.stream.listen(onDataActually);
159152

160153
// Add initial action
161-
actionController.add(WrapperAction(null, ActionType.initial));
154+
actionController.add(WrapperAction.initial);
162155

163156
// Listening to upstream actions
164-
final subscriptionUpstream = stream
165-
.map((action) => WrapperAction(action, ActionType.external))
166-
.listen(
167-
actionController.add,
168-
onError: controller.addError,
169-
onDone: controller.close,
170-
);
157+
final subscriptionUpstream =
158+
stream.map((action) => WrapperAction.external(action)).listen(
159+
actionController.add,
160+
onError: controller.addError,
161+
onDone: controller.close,
162+
);
171163

172164
final getState = () => state;
165+
final actionStream = actionController.stream
166+
.map((wrapper) => wrapper.action<A>())
167+
.asBroadcastStream(onCancel: (s) => s.cancel());
173168

174169
subscriptions = [
175-
..._listenSideEffects(actionController, getState, controller),
170+
..._listenSideEffects(
171+
actionController, getState, controller, actionStream),
176172
subscriptionUpstream,
177-
subscriptionActionController
173+
subscriptionActionController,
178174
];
179175
}
180176

181177
Future<void> onCancel() async {
182-
final future = actionController?.close();
178+
final future = _actionController?.close();
183179
final cancelFutures = subscriptions?.map((s) => s.cancel());
184180
final futures = [...?cancelFutures, if (future != null) future];
185181

@@ -199,38 +195,35 @@ class ReduxStoreStreamTransformer<A, S> extends StreamTransformerBase<A, S> {
199195
controller = StreamController<S>(
200196
sync: true,
201197
onListen: onListen,
202-
onPause: () => subscriptions.forEach((s) => s.pause()),
203-
onResume: () => subscriptions.forEach((s) => s.resume()),
198+
onPause: () => subscriptions?.forEach((s) => s.pause()),
199+
onResume: () => subscriptions?.forEach((s) => s.resume()),
204200
onCancel: onCancel,
205201
);
206202
}
207203

208204
return controller.stream;
209205
}
210206

211-
Iterable<StreamSubscription<dynamic>> _listenSideEffects(
212-
StreamController<WrapperAction<A>> actionController,
207+
Iterable<StreamSubscription<Object?>> _listenSideEffects(
208+
StreamController<WrapperAction> actionController,
213209
GetState<S> getState,
214-
StreamController<S> controller,
210+
StreamController<S> stateController,
211+
Stream<A> actionStream,
215212
) {
216213
return _sideEffects.mapIndexed(
217214
(index, sideEffect) {
218215
Stream<A> actions;
219216
try {
220-
actions = sideEffect(
221-
actionController.stream.map((wrapper) => wrapper.action),
222-
getState,
223-
);
217+
actions = sideEffect(actionStream, getState);
224218
} catch (e, s) {
225219
actions = Stream.error(e, s);
226220
}
227221

228222
return actions
229-
.map(
230-
(action) => WrapperAction(action, ActionType.sideEffect(index)))
223+
.map((action) => WrapperAction.sideEffect(action, index))
231224
.listen(
232225
actionController.add,
233-
onError: controller.addError,
226+
onError: stateController.addError,
234227
// Swallow onDone because just if one SideEffect reaches onDone
235228
// we don't want to make everything incl. ReduxStore and other SideEffects reach onDone
236229
);

0 commit comments

Comments
 (0)