-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathexample.dart
126 lines (118 loc) · 3.65 KB
/
example.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import 'package:functional_flutter/functional_flutter.dart';
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
void main() {
// The following app has two views, one that shows countA and one that shows
// countB. Depending on the value of showingA, countA or countB is rendered.
// If countA is incremented when countB is showing then the pure wrapper
// will not rebuild the counterView widget.
runApp(counterApp('functional flutter example'));
}
@immutable
class AppState {
final bool showingA;
final int countA;
final int countB;
AppState({
this.showingA: true,
this.countA: 0,
this.countB: 0,
});
AppState clone({
bool showingA,
int countA,
int countB,
}) =>
new AppState(
showingA: showingA ?? this.showingA,
countA: countA ?? this.countA,
countB: countB ?? this.countB,
);
}
@immutable
class AppProps {
final String title;
final AppState state;
final VoidCallback incrementA;
final VoidCallback incrementB;
final VoidCallback changView;
AppProps({
this.title,
this.state,
this.incrementA,
this.incrementB,
this.changView,
});
}
// counterApp is a functional component that wraps appContent
// in a statefult widget.
FunctionalWidget<String> counterApp = withState(
// default state
new AppState(),
// maps the incoming props, the state from the stateful widget
// and the setState function from the stateful widget to AppProps,
// the result of this function is passed to appContent when counterApp
// is invoked.
(String props, AppState state, SetState<AppState> setState) => new AppProps(
title: props,
state: state,
incrementA: () => setState((s) => s.clone(countA: s.countA + 1)),
incrementB: () => setState((s) => s.clone(countB: s.countB + 1)),
changView: () => setState((s) => s.clone(showingA: !s.showingA)),
),
)(appContent);
// appContent is a functional widget that takes AppProps
// and renders the content of the application, which is
// 3 buttons that update the app state and the current view
Widget appContent(AppProps props) => new MaterialApp(
title: props.title,
home: new Scaffold(
body: new ListView(children: <Widget>[
new RaisedButton(
onPressed: props.changView,
child: new Row(
children: <Widget>[
new Text('Change View'),
],
),
),
new RaisedButton(
onPressed: props.incrementA,
child: new Row(
children: <Widget>[
new Text('Increment A'),
],
),
),
new RaisedButton(
onPressed: props.incrementB,
child: new Row(
children: <Widget>[
new Text('Increment B'),
],
),
),
viewBranch(props),
]),
),
);
// viewBranch is a functional widget that gen AppProps returns
// a view that displays either counterA or counterB's value.
// Both counterView widgets are 'pure' meaning they won't rebuild
// if their props do not change. For example, if increment B is clicked
// in the parent widget and showingA is true, the build function for
// the Text widget will not be run again since the value of countA didn't change
FunctionalWidget<AppProps> viewBranch = branch(
(props) => props.state.showingA,
withProps<int, AppProps>((props) => props.state.countA)(
pure(
counterView,
),
),
withProps<int, AppProps>((props) => props.state.countB)(
pure(
counterView,
),
),
);
Widget counterView(int count) => new Text('Count $count');