Skip to content

Instantly share code, notes, and snippets.

@riskers
Last active December 25, 2019 02:10
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save riskers/f05e8ad1f2dd5e07ccd0ad86fe82e26f to your computer and use it in GitHub Desktop.
Save riskers/f05e8ad1f2dd5e07ccd0ad86fe82e26f to your computer and use it in GitHub Desktop.
flutter redux demo
// https://github-riskers-blog.oss-cn-qingdao.aliyuncs.com/20190117210031.gif
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:redux_thunk/redux_thunk.dart';
import 'package:flutter_redux/flutter_redux.dart';
class AppState {
final int count;
final int clickCount;
AppState({
this.count,
this.clickCount,
});
// https://github.com/johnpryan/redux.dart/issues/21
AppState copyWith({count, clickCount}) {
return AppState(
count: count ?? this.count,
clickCount: clickCount ?? this.clickCount,
);
}
}
// actions
enum Actions {
Click,
Increment,
Decrement,
}
// reducers:
AppState counterReducer(AppState state, dynamic action) {
switch (action) {
case Actions.Increment:
return state.copyWith(count: state.count + 1);
case Actions.Decrement:
return state.copyWith(count: state.count - 1);
}
return state;
}
AppState valueReducer(AppState state, dynamic action) {
if (action == Actions.Click) {
return state.copyWith(clickCount: state.clickCount + 1);
}
return state;
}
final reducers = combineReducers<AppState>([
counterReducer,
valueReducer,
]);
void main() {
// store:
final store = new Store<AppState>(
reducers,
middleware: [thunkMiddleware],
initialState: AppState(
count: 0,
clickCount: 0,
),
);
runApp(FlutterReduxApp(
title: 'Flutter Redux Demo',
store: store,
));
}
class AppStateViewModel {
final AppState state;
final void Function() onClick;
AppStateViewModel({
this.state,
this.onClick,
});
}
class SimpleText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, AppStateViewModel>(
converter: (store) {
return AppStateViewModel(
state: store.state,
);
},
builder: (context, vm) {
String count = vm.state.count.toString();
String clickCount = vm.state.clickCount.toString();
return new Text(
'count: $count, clickCount: $clickCount',
style: Theme.of(context).textTheme.subhead,
);
},
);
}
}
class AddButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, AppStateViewModel>(
converter: (store) {
return AppStateViewModel(
onClick: () {
store.dispatch(Actions.Increment);
store.dispatch(Actions.Click);
}
);
},
builder: (context, vm) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: new FloatingActionButton(
// Attach the `callback` to the `onPressed` attribute
onPressed: vm.onClick,
tooltip: 'Increment',
child: new Icon(Icons.exposure_plus_1),
),
);
},
);
}
}
class DesButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, AppStateViewModel>(
converter: (store) {
return AppStateViewModel(
onClick: () {
store.dispatch(Actions.Decrement);
}
);
},
builder: (context, vm) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: new FloatingActionButton(
// Attach the `callback` to the `onPressed` attribute
onPressed: vm.onClick,
tooltip: 'des',
child: new Icon(Icons.exposure_neg_1),
),
);
},
);
}
}
class FlutterReduxApp extends StatelessWidget {
final Store<AppState> store;
final String title;
FlutterReduxApp({Key key, this.store, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
// The StoreProvider should wrap your MaterialApp or WidgetsApp. This will
// ensure all routes have access to the store.
return new StoreProvider<AppState>(
// Pass the store to the StoreProvider. Any ancestor `StoreConnector`
// Widgets will find and use this value as the `Store`.
store: store,
child: MaterialApp(
theme: ThemeData.dark(),
title: title,
home: Scaffold(
appBar: AppBar(
title: new Text(title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Text(
'You have pushed the button this many times:',
),
// Connect the Store to a Text Widget that renders the current
// count.
//
// We'll wrap the Text Widget in a `StoreConnector` Widget. The
// `StoreConnector` will find the `Store` from the nearest
// `StoreProvider` ancestor, convert it into a String of the
// latest count, and pass that String to the `builder` function
// as the `count`.
//
// Every time the button is tapped, an action is dispatched and
// run through the reducer. After the reducer updates the state,
// the Widget will be automatically rebuilt with the latest
// count. No need to manually manage subscriptions or Streams!
SimpleText(),
],
),
),
// Connect the Store to a FloatingActionButton. In this case, we'll
// use the Store to build a callback that with dispatch an Increment
// Action.
//
// Then, we'll pass this callback to the button's `onPressed` handler.
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
AddButton(),
DesButton(),
],
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:redux_thunk/redux_thunk.dart';
import 'package:flutter_redux/flutter_redux.dart';
enum Actions { Increment }
// The reducer, which takes the previous count and increments it in response
// to an Increment action.
int counterReducer(int state, dynamic action) {
if (action == Actions.Increment) {
return state + 1;
}
return state;
}
void main() {
// 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<int>(
counterReducer,
middleware: [thunkMiddleware],
initialState: 0
);
runApp(FlutterReduxApp(
title: 'Flutter Redux Demo',
store: store,
));
}
class Simple extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<int, String>(
converter: (store) => store.state.toString(),
builder: (context, count) {
return new Text(
count,
style: Theme.of(context).textTheme.display1,
);
},
);
}
}
class AddButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<int, VoidCallback>(
converter: (store) {
// Return a `VoidCallback`, which is a fancy name for a function
// with no parameters. It only dispatches an Increment action.
return () => store.dispatch(Actions.Increment);
},
builder: (context, callback) {
return new FloatingActionButton(
// Attach the `callback` to the `onPressed` attribute
onPressed: callback,
tooltip: 'Increment',
child: new Icon(Icons.add),
);
},
);
}
}
class FlutterReduxApp extends StatelessWidget {
final Store<int> store;
final String title;
FlutterReduxApp({Key key, this.store, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
// The StoreProvider should wrap your MaterialApp or WidgetsApp. This will
// ensure all routes have access to the store.
return 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: MaterialApp(
theme: ThemeData.dark(),
title: title,
home: Scaffold(
appBar: AppBar(
title: new Text(title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Text(
'You have pushed the button this many times:',
),
// Connect the Store to a Text Widget that renders the current
// count.
//
// We'll wrap the Text Widget in a `StoreConnector` Widget. The
// `StoreConnector` will find the `Store` from the nearest
// `StoreProvider` ancestor, convert it into a String of the
// latest count, and pass that String to the `builder` function
// as the `count`.
//
// Every time the button is tapped, an action is dispatched and
// run through the reducer. After the reducer updates the state,
// the Widget will be automatically rebuilt with the latest
// count. No need to manually manage subscriptions or Streams!
Simple(),
],
),
),
// Connect the Store to a FloatingActionButton. In this case, we'll
// use the Store to build a callback that with dispatch an Increment
// Action.
//
// Then, we'll pass this callback to the button's `onPressed` handler.
floatingActionButton: AddButton(),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:redux/redux.dart';
import 'package:redux_thunk/redux_thunk.dart';
import 'package:flutter_redux/flutter_redux.dart';
class AppState {
final int count;
final int clickCount;
AppState({
this.count,
this.clickCount,
});
AppState copyWith({count, clickCount}) {
return AppState(
count: count ?? this.count,
clickCount: clickCount ?? this.clickCount,
);
}
}
enum Actions {
Click,
Increment,
Decrement,
}
ThunkAction<AppState> asyncIncrement() {
return (Store<AppState> store) async {
await Future.delayed(Duration(seconds: 2));
store.dispatch(Actions.Increment);
};
}
AppState counterReducer(AppState state, dynamic action) {
switch (action) {
case Actions.Increment:
return state.copyWith(count: state.count + 1);
case Actions.Decrement:
return state.copyWith(count: state.count - 1);
}
return state;
}
AppState valueReducer(AppState state, dynamic action) {
if (action == Actions.Click) {
return state.copyWith(clickCount: state.clickCount + 1);
}
return state;
}
final reducers = combineReducers<AppState>([
counterReducer,
valueReducer,
]);
void main() {
final store = new Store<AppState>(
reducers,
middleware: [thunkMiddleware],
initialState: AppState(
count: 0,
clickCount: 0,
),
);
runApp(FlutterReduxApp(
title: 'Flutter Redux Demo',
store: store,
));
}
class AppStateViewModel {
final AppState state;
final void Function() onClick;
AppStateViewModel({
this.state,
this.onClick,
});
}
class SimpleText extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, AppStateViewModel>(
converter: (store) {
return AppStateViewModel(
state: store.state,
);
},
builder: (context, vm) {
String count = vm.state.count.toString();
String clickCount = vm.state.clickCount.toString();
return new Text(
'count: $count, clickCount: $clickCount',
style: Theme.of(context).textTheme.subhead,
);
},
);
}
}
class AddButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, AppStateViewModel>(
converter: (store) {
return AppStateViewModel(
onClick: () {
store.dispatch(Actions.Increment);
store.dispatch(Actions.Click);
}
);
},
builder: (context, vm) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: new FloatingActionButton(
// Attach the `callback` to the `onPressed` attribute
onPressed: vm.onClick,
tooltip: 'Increment',
child: new Icon(Icons.exposure_plus_1),
),
);
},
);
}
}
class AddAsyncButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, AppStateViewModel>(
converter: (store) {
return AppStateViewModel(
onClick: () {
store.dispatch(asyncIncrement());
store.dispatch(Actions.Click);
}
);
},
builder: (context, vm) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: new FloatingActionButton(
// Attach the `callback` to the `onPressed` attribute
onPressed: vm.onClick,
tooltip: 'Increment',
child: new Icon(Icons.slow_motion_video),
),
);
},
);
}
}
class DesButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StoreConnector<AppState, AppStateViewModel>(
converter: (store) {
return AppStateViewModel(
onClick: () {
store.dispatch(Actions.Decrement);
}
);
},
builder: (context, vm) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: new FloatingActionButton(
// Attach the `callback` to the `onPressed` attribute
onPressed: vm.onClick,
tooltip: 'des',
child: new Icon(Icons.exposure_neg_1),
),
);
},
);
}
}
class FlutterReduxApp extends StatelessWidget {
final Store<AppState> store;
final String title;
FlutterReduxApp({Key key, this.store, this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return new StoreProvider<AppState>(
store: store,
child: MaterialApp(
theme: ThemeData.dark(),
title: title,
home: Scaffold(
appBar: AppBar(
title: new Text(title),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
new Text(
'You have pushed the button this many times:',
),
SimpleText(),
],
),
),
// Connect the Store to a FloatingActionButton. In this case, we'll
// use the Store to build a callback that with dispatch an Increment
// Action.
//
// Then, we'll pass this callback to the button's `onPressed` handler.
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
AddButton(),
DesButton(),
AddAsyncButton(),
],
),
),
),
);
}
}
@riskers
Copy link
Author

riskers commented Jan 17, 2019

redux-combine:

redux-combine

redux-thunk:

redux-thunk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment