Skip to content
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

## 3.0.0
Migrate w_flux to null-safety.

## 2.11.0
Create ActionV2 class with non-nullable payloads in preparation for null-safety.
Expand Down
9 changes: 2 additions & 7 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@ analyzer:
exclude:
- "example/**"

# Strong mode is required. Applies to the current project.
strong-mode:
# When compiling to JS, both implicit options apply to the current
# project and all dependencies. They are useful to find possible
# Type fixes or areas for explicit typing.
implicit-casts: true
implicit-dynamic: true
language:
strict-casts: true

# ALL lint rules are included. Unused lints should be commented
# out with a reason. An up to date list of all options is here
Expand Down
6 changes: 2 additions & 4 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,17 @@ description: Flux library for uni-directional dataflow inspired by reflux and Fa
homepage: https://github.com/Workiva/w_flux
publish_to: none
environment:
sdk: ">=2.11.0 <3.0.0"
sdk: '>=2.12.0 <3.0.0'
dependencies:
over_react: ">=3.12.0 <5.0.0"
w_flux:

dev_dependencies:
react: ">=5.7.0 <7.0.0"
react: ^7.0.0
build_runner: ^2.0.0
build_web_compilers: ^3.0.0
dart_dev: ^4.0.0
dart_style: ^2.1.1
dependency_validator: ^3.0.0


dependency_overrides:
w_flux:
Expand Down
5 changes: 1 addition & 4 deletions example/web/random_color/random_color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import 'dart:html';
import 'dart:math';

import 'package:react/react.dart' as react;
import 'package:over_react/over_react.dart';
import 'package:react/react_dom.dart' as react_dom;
import 'package:react/react_client.dart' as react_client;

Expand All @@ -31,9 +30,7 @@ main() async {

// render the component
react_client.setClientConfiguration();
react_dom.render(
ErrorBoundary()(
RandomColorComponent({'actions': actions, 'store': store})),
react_dom.render(RandomColorComponent({'actions': actions, 'store': store}),
querySelector('#content-container'));
}

Expand Down
4 changes: 2 additions & 2 deletions example/web/todo_app/components/new_todo_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import 'package:react/react.dart' as react;
var NewTodoInput = react.registerComponent(() => _NewTodoInput());

class _NewTodoInput extends react.Component2 {
String get value => state['value'];
Function get onSubmit => props['onSubmit'];
String get value => state['value'] as String;
Function get onSubmit => props['onSubmit'] as Function;

get initialState => {'value': ''};

Expand Down
2 changes: 1 addition & 1 deletion example/web/todo_app/components/todo_app_component.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class _ToDoAppComponent extends FluxComponent<ToDoActions, ToDoStore> {
this.actions.createTodo(Todo(value));
}

_completeTodo(todo) {
_completeTodo(Todo todo) {
this.actions.completeTodo(todo);
}
}
4 changes: 2 additions & 2 deletions example/web/todo_app/components/todo_list_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import '../store.dart';
var TodoListItem = react.registerComponent(() => _TodoListItem());

class _TodoListItem extends react.Component2 {
Todo get todo => props['todo'];
Function get onClick => props['onClick'];
Todo get todo => props['todo'] as String;
Function get onClick => props['onClick'] as Function;

get defaultProps => {'todo': null};

Expand Down
11 changes: 5 additions & 6 deletions example/web/todo_app/store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,17 @@ import 'actions.dart';

class ToDoStore extends Store {
/// Public data
List<Todo> _todos;
List<Todo> _todos = [];
List<Todo> get todos => _todos;

/// Internals
ToDoActions _actions;

ToDoStore(ToDoActions this._actions) {
_todos = [];

triggerOnActionV2(_actions.createTodo, (todo) => _todos.add(todo));
triggerOnActionV2(_actions.completeTodo, (todo) => todo.completed = true);
triggerOnActionV2(_actions.deleteTodo, (todo) => _todos.remove(todo));
triggerOnActionV2(_actions.createTodo, (Todo todo) => _todos.add(todo));
triggerOnActionV2(
_actions.completeTodo, (Todo todo) => todo.completed = true);
triggerOnActionV2(_actions.deleteTodo, (Todo todo) => _todos.remove(todo));
triggerOnActionV2(_actions.clearTodoList, (_) => _todos = []);
}
}
Expand Down
3 changes: 1 addition & 2 deletions example/web/todo_app/todo_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ main() async {

// render the component
react_client.setClientConfiguration();
react_dom.render(
ErrorBoundary()(ToDoAppComponent({'actions': actions, 'store': store})),
react_dom.render(ToDoAppComponent({'actions': actions, 'store': store}),
querySelector('#content-container'));
}
8 changes: 4 additions & 4 deletions lib/src/action.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import 'package:w_flux/src/constants.dart' show v3Deprecation;
/// Like [ActionV2], but payloads cannot be made non-nullable since the argument
/// to [call] is optional.
@Deprecated('Use ActionV2 instead, which supports non-nullable payloads.')
class Action<T> extends ActionV2<T> {
class Action<T> extends ActionV2<T?> {
@override
String get disposableTypeName => 'Action';

@override
Future call([T payload]) => super.call(payload);
Future call([T? payload]) => super.call(payload);
}

/// A command that can be dispatched and listened to.
Expand Down Expand Up @@ -113,14 +113,14 @@ typedef _ActionListener<T> = dynamic Function(T event);

/// A subscription used to cancel registered listeners to an [ActionV2].
class ActionSubscription {
Function _onCancel;
Function? _onCancel;

ActionSubscription(this._onCancel);

/// Cancel this subscription to an [ActionV2]
void cancel() {
if (_onCancel != null) {
_onCancel();
_onCancel!();
_onCancel = null;
}
}
Expand Down
10 changes: 5 additions & 5 deletions lib/src/mixins/batched_redraws.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ class _RedrawScheduler implements Function {
Map<BatchedRedraws, List<Function>> _components =
<BatchedRedraws, List<Function>>{};

void call(BatchedRedraws component, [callback()]) {
void call(BatchedRedraws component, [callback()?]) {
if (_components.isEmpty) {
_tick();
}

_components[component] ??= [];

if (callback != null) _components[component].add(callback);
if (callback != null) _components[component]!.add(callback);
}

Future _tick() async {
Expand All @@ -33,7 +33,7 @@ class _RedrawScheduler implements Function {
continue;
}

Function() chainedCallbacks;
Function()? chainedCallbacks;

if (callbacks.isNotEmpty) {
chainedCallbacks = () {
Expand All @@ -43,7 +43,7 @@ class _RedrawScheduler implements Function {
};
}

(component as react.Component)?.setState({}, chainedCallbacks);
(component as react.Component).setState({}, chainedCallbacks);

// Waits a tick to prevent holding up the thread, allowing other scripts to execute in between each component.
await Future(() {});
Expand All @@ -67,5 +67,5 @@ _RedrawScheduler _scheduleRedraw = _RedrawScheduler();
class BatchedRedraws {
bool shouldBatchRedraw = true;

void redraw([callback()]) => _scheduleRedraw(this, callback);
void redraw([callback()?]) => _scheduleRedraw(this, callback);
}
11 changes: 6 additions & 5 deletions lib/src/store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ class Store extends Stream<Store> with Disposable {
final StreamController<Store> _streamController;

/// Broadcast stream of "data updated" events. Listened to in [listen].
Stream<Store> _stream;
/// Use of late is ok because we guarantee that it is set in each constructor.
late Stream<Store> _stream;

/// Construct a new [Store] instance.
Store() : _streamController = StreamController<Store>.broadcast() {
Expand Down Expand Up @@ -94,8 +95,8 @@ class Store extends Stream<Store> with Disposable {
/// It is the caller's responsibility to cancel the subscription when
/// needed.
@override
StreamSubscription<Store> listen(StoreHandler onData,
{Function onError, void onDone(), bool cancelOnError}) {
StreamSubscription<Store> listen(StoreHandler? onData,
{Function? onError, void onDone()?, bool? cancelOnError}) {
if (isDisposed) {
throw StateError('Store of type $runtimeType has been disposed');
}
Expand Down Expand Up @@ -141,7 +142,7 @@ class Store extends Stream<Store> with Disposable {
/// Deprecated: 2.9.5
/// To be removed: 3.0.0
@deprecated
triggerOnAction(ActionV2 action, [void onAction(payload)]) {
triggerOnAction(ActionV2 action, [void onAction(payload)?]) {
triggerOnActionV2(action, onAction);
}

Expand All @@ -154,7 +155,7 @@ class Store extends Stream<Store> with Disposable {
///
/// If the `Store` has been disposed, this method throws a [StateError].
void triggerOnActionV2<T>(ActionV2<T> action,
[FutureOr<dynamic> onAction(T payload)]) {
[FutureOr<dynamic> onAction(T payload)?]) {
if (isOrWillBeDisposed) {
throw StateError('Store of type $runtimeType has been disposed');
}
Expand Down
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ description: Flux library for uni-directional dataflow inspired by reflux and Fa
homepage: https://github.com/Workiva/w_flux

environment:
sdk: ">=2.11.0 <3.0.0"
sdk: '>=2.12.0 <3.0.0'

dependencies:
meta: ^1.6.0
react: ">=5.7.0 <7.0.0"
react: ^7.0.0
w_common: ^3.0.0

dev_dependencies:
Expand Down
22 changes: 11 additions & 11 deletions test/action_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import 'package:test/test.dart';

void main() {
group('Action', () {
Action<String> action;
late Action<String> action;

setUp(() {
action = Action<String>();
Expand All @@ -47,7 +47,7 @@ void main() {

test('should support dispatch by default when called with a payload',
() async {
action.listen(expectAsync1((String payload) {
action.listen(expectAsync1((String? payload) {
expect(payload, equals('990 guerrero'));
}));

Expand Down Expand Up @@ -107,7 +107,7 @@ void main() {
});
});

var future = action();
Future<dynamic>? future = action();
expect(asyncListenerCompleted, isFalse);

await future;
Expand Down Expand Up @@ -182,8 +182,8 @@ void main() {

stopwatch.reset();

Completer syncCompleter;
Completer asyncCompleter;
late Completer syncCompleter;
late Completer asyncCompleter;
var action = Action()
..listen((_) => syncCompleter.complete())
..listen((_) async {
Expand All @@ -207,7 +207,7 @@ void main() {
});

group('ActionV2', () {
ActionV2<String> action;
late ActionV2<String> action;

setUp(() {
action = ActionV2<String>();
Expand Down Expand Up @@ -280,7 +280,7 @@ void main() {
});
});

Future<dynamic> future = action('payload');
Future<dynamic>? future = action('payload');
expect(asyncListenerCompleted, isFalse);

await future;
Expand Down Expand Up @@ -352,8 +352,8 @@ void main() {

stopwatch.reset();

Completer syncCompleter;
Completer asyncCompleter;
late Completer syncCompleter;
late Completer asyncCompleter;
var action = ActionV2()
..listen((_) => syncCompleter.complete())
..listen((_) async {
Expand All @@ -377,7 +377,7 @@ void main() {
});

group('Null typed', () {
ActionV2<Null> nullAction;
late ActionV2<Null> nullAction;

setUp(() {
nullAction = ActionV2<Null>();
Expand All @@ -394,7 +394,7 @@ void main() {
});

group('void typed', () {
ActionV2<void> voidAction;
late ActionV2<void> voidAction;

setUp(() {
voidAction = ActionV2<void>();
Expand Down
6 changes: 3 additions & 3 deletions test/component_server_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ class TestDefaultComponent extends FluxComponent {

render() => react.div({});

redraw([callback()]) {
redraw([callback()?]) {
numberOfRedraws += 1;
}
}
Expand All @@ -212,7 +212,7 @@ class TestRedrawOnComponent extends FluxComponent<TestActions, TestStores> {

redrawOn() => [store.store1, store.store2];

redraw([callback()]) {
redraw([callback()?]) {
numberOfRedraws += 1;
}
}
Expand All @@ -231,7 +231,7 @@ class TestHandlerPrecedence extends FluxComponent<TestActions, TestStores> {
numberOfHandlerCalls += 1;
}

redraw([callback()]) {
redraw([callback()?]) {
numberOfRedraws += 1;
}
}
Loading