Skip to content

Commit

Permalink
0.4.0 - Dart2 Support with Stronger Typing (#20)
Browse files Browse the repository at this point in the history
* 0.4.0 - Dart2 Support with Stronger Typing
  • Loading branch information
brianegan committed Mar 19, 2018
1 parent 572d9ea commit 0666a11
Show file tree
Hide file tree
Showing 15 changed files with 18,061 additions and 240 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ addons:
- libstdc++6
- fonts-droid
before_script:
- git clone https://github.com/flutter/flutter.git -b beta --depth 1
- git clone https://github.com/flutter/flutter.git -b master --depth 1
- ./flutter/bin/flutter doctor
script:
- ./flutter/bin/flutter test --coverage --coverage-path=lcov.info
- ./flutter/bin/flutter test --preview-dart-2 --coverage --coverage-path=lcov.info
after_success:
- bash <(curl -s https://codecov.io/bash)
cache:
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## 0.4.0

* Works with Dart 2 (no longer supports Dart 1)
* Stronger Type info Required
* Breaking Changes:
* `StoreProvider` now requires generic type info: `new StoreProvider<AppState>`
* `new StoreProvider.of(context).store` is now `StoreProvider.of<AppState>(context)`

## 0.3.6

* Add `onWillChange`. This function will be called before the builder and can be used for working with Imperative APIs, such as Navigator, TextEditingController, or TabController.

## 0.3.6

* Add `onWillChange`. This function will be called before the builder and can be used for working with Imperative APIs, such as Navigator, TextEditingController, or TabController.
Expand Down
70 changes: 47 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@
A set of utilities that allow you to easily consume a [Redux](https://pub.dartlang.org/packages/redux) Store to build Flutter Widgets.

This package is built to work with [Redux.dart](https://pub.dartlang.org/packages/redux).

## Redux Widgets

* `StoreProvider` - The base Widget. It will pass the given Redux Store to all descendants that request it.
* `StoreBuilder` - A descendant Widget that gets the Store from a `StoreProvider` and passes it to a Widget `builder` function.
* `StoreConnector` - A descendant Widget that gets the Store from the nearest `StoreProvider` ancestor, converts the `Store` into a `ViewModel` with the given `converter` function, and passes the `ViewModel` to a `builder` function. Any time the Store emits a change event, the Widget will automatically be rebuilt. No need to manage subscriptions!

## Dart Support

* Dart 1: 0.3.x
* Dart 2: 0.4.0+. See the migration guide below!

## Dart 2 Migration Guide

Dart 2 requires more strict typing (yay!), and gives us the option to make getting the Store from the StoreProvider more convenient!

1. Change `new StoreProvider(...)` to `new StoreProvider<StateClass>(...)` in your Widget tree.
2. Change `new StoreProvider.of(context).store` to `StoreProvider.of<StateClass>(context)` if you're directly fetching the `Store<AppState>` yourself from the `StoreProvider<AppState>`. No need to access the `store` field directly any more since Dart 2 can now infer the proper type with a static function :)

## Examples

* [Simple example](https://gitlab.com/brianegan/flutter_redux/tree/master/example) - a port of the standard "Counter Button" example from Flutter
Expand All @@ -26,17 +38,19 @@ This package is built to work with [Redux.dart](https://pub.dartlang.org/package

Let's demo the basic usage with the all-time favorite: A counter example!

Note: This example requires flutter_redux 0.4.0+ and Dart 2! If you're using Dart 1, [see the old example](https://github.com/brianegan/flutter_redux/blob/eb4289795a5a70517686ccd1d161abdb8cc08af5/example/lib/main.dart).

```dart
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
// One simple action: Increment
enum Actions { Increment }
// The reducer, which takes the previous count and increments it in response
// to an Increment action.
int counterReducer(int state, action) {
int counterReducer(int state, dynamic action) {
if (action == Actions.Increment) {
return state + 1;
}
Expand All @@ -45,23 +59,29 @@ int counterReducer(int state, action) {
}
void main() {
runApp(new FlutterReduxApp());
// Create your store as a final variable in a base Widget. This works better
// with Hot Reload than creating it directly in the `build` function.
final store = Store<int>(counterReducer, initialState: 0);
runApp(new FlutterReduxApp(
title: 'Flutter Redux Demo',
store: store,
));
}
class FlutterReduxApp extends StatelessWidget {
// Create your store as a final variable in a base Widget. This works better
// with Hot Reload than creating it directly in the `build` function.
final store = new Store(counterReducer, initialState: 0);
final Store<int> store;
final String title;
FlutterReduxApp({Key key, this.store, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
final title = 'Flutter Redux Demo';
return new MaterialApp(
theme: new ThemeData.dark(),
title: title,
home: new StoreProvider(
// Pass the store to the StoreProvider. Any descendant `StoreConnector`
home: new StoreProvider<int>(
// Pass the store to the StoreProvider. Any ancestor `StoreConnector`
// Widgets will find and use this value as the `Store`.
store: store,
child: new Scaffold(
Expand Down Expand Up @@ -90,10 +110,12 @@ class FlutterReduxApp extends StatelessWidget {
// count. No need to manually manage subscriptions or Streams!
new StoreConnector<int, String>(
converter: (store) => store.state.toString(),
builder: (context, count) => new Text(
count,
style: Theme.of(context).textTheme.display1,
),
builder: (context, count) {
return new Text(
count,
style: Theme.of(context).textTheme.display1,
);
},
)
],
),
Expand All @@ -109,21 +131,23 @@ class FlutterReduxApp extends StatelessWidget {
// with no parameters. It only dispatches an Increment action.
return () => store.dispatch(Actions.Increment);
},
builder: (context, callback) => new FloatingActionButton(
// Attach the `callback` to the `onPressed` attribute
onPressed: callback,
tooltip: 'Increment',
child: new Icon(Icons.add),
),
builder: (context, callback) {
return new FloatingActionButton(
// Attach the `callback` to the `onPressed` attribute
onPressed: callback,
tooltip: 'Increment',
child: new Icon(Icons.add),
);
},
),
),
),
);
}
}
```
```

### Purpose
## Purpose

One question that [reasonable people might ask](https://www.reddit.com/r/FlutterDev/comments/6vscdy/a_set_of_utilities_that_allow_you_to_easily/dm3ll7d/): Why do you need all of this if `StatefulWidget` exists?

Expand Down
4 changes: 3 additions & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
analyzer:
strong-mode: true
strong-mode:
implicit-casts: false
implicit-dynamic: false
1 change: 1 addition & 0 deletions example/ios/Flutter/flutter_assets/AssetManifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions example/ios/Flutter/flutter_assets/FontManifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"fonts":[{"asset":"fonts/MaterialIcons-Regular.ttf"}],"family":"MaterialIcons"}]
Loading

0 comments on commit 0666a11

Please sign in to comment.