Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: sky/sdk/lib/framework/fn.md

Issue 1189323002: Remove fn.md (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: add link to new frameowkr Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/sdk/lib/framework/README.md ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 Sky Framework
2 =============
3
4 (This file applies to fn.dart, which we are in the process of porting
5 to a new architecture.)
6
7 Effen is a functional-reactive framework for Sky which takes inspiration from
8 [React](http://facebook.github.io/react/). Effen is comprised of three main
9 parts: a virtual-dom and diffing engine, a component mechanism and a very early
10 set of widgets for use in creating applications.
11
12 The central idea is that you build your UI out of components. Components
13 describe what their view should look like given their current configuration &
14 state. The diffing engine ensures that the DOM looks how the component describes
15 by applying minimal diffs to transition it from one state to the next.
16
17 If you just want to dive into code, see the [stocks example](../../../../example s/stocks).
18
19 Hello World
20 -----------
21
22 To build an application, create a subclass of App and instantiate it.
23
24 ```HTML
25 <script>
26 import 'hello_world.dart';
27
28 main() {
29 new HelloWorldApp();
30 }
31 </script>
32 ```
33
34 ```dart
35 // In hello_world.dart
36 import 'package:sky/framework/fn.dart';
37
38 class HelloWorldApp extends App {
39 UINode build() {
40 return new Text('Hello, world!');
41 }
42 }
43 ```
44
45 An app is comprised of (and is, itself, a) components. A component's main job is
46 to implement `UINode build()`. The idea here is that the `build` method describe s
47 the DOM of a component at any given point during its lifetime. In this case, our
48 `HelloWorldApp`'s `build` method just returns a `Text` node which displays the
49 obligatory line of text.
50
51 Nodes
52 -----
53
54 A component's `build` method must return a single `UINode` which *may* have
55 children (and so on, forming a *subtree*). Effen comes with a few built-in nodes
56 which mirror the built-in nodes/elements of sky: `Text`, `Anchor` (`<a />`,
57 `Image` (`<img />`) and `Container` (`<div />`). `build` can return a tree of
58 Nodes comprised of any of these nodes and plus any other imported object which
59 extends `Component`.
60
61 How to structure you app
62 ------------------------
63
64 If you're familiar with React, the basic idea is the same: Application data
65 flows *down* from components which have data to components & nodes which they
66 construct via construction parameters. Generally speaking, View-Model data (data
67 which is derived from *model* data, but exists only because the view needs it),
68 is computed during the course of `build` and is short-lived, being handed into
69 nodes & components as configuration data.
70
71 What does "data flowing down the tree" mean?
72 --------------------------------------------
73
74 Consider the case of a checkbox. (i.e. `widgets/checkbox.dart`). The `Checkbox`
75 constructor looks like this:
76
77 ```dart
78 ValueChanged onChanged;
79 bool checked;
80
81 Checkbox({ Object key, this.onChanged, this.checked }) : super(key: key);
82 ```
83
84 What this means is that the `Checkbox` component *never* "owns" the state of
85 the checkbox. It's current state is handed into the `checked` parameter, and
86 when a click occurs, the checkbox invokes its `onChanged` callback with the
87 value it thinks it should be changed to -- but it never directly changes the
88 value itself. This is a bit odd at first look, but if you think about it: a
89 control isn't very useful unless it gets its value out to someone and if you
90 think about databinding, the same thing happens: databinding basically tells a
91 control to *treat some remote variable as its storage*. That's all that is
92 happening here. In this case, some owning component probably has a set of values
93 which describe a form.
94
95 Stateful vs. Stateless components
96 ---------------------------------
97
98 All components have access to two kinds of state: (1) configuration data
99 (constructor arguments) and (2) private data (data they mutate themselves).
100 While react components have explicit property bags for these two kinds of state
101 (`this.prop` and `this.state`), Effen maps these ideas to the public and private
102 fields of the component. Constructor arguments should (by convention) be
103 reflected as public fields of the component and state should only be set on
104 private (with a leading underbar `_`) fields.
105
106 All (non-component) Effen nodes are stateless. Some components will be stateful.
107 This state will likely encapsulate transient states of the UI, such as scroll
108 position, animation state, uncommitted form values, etc...
109
110 A component can become stateful in two ways: (1) by passing `super(stateful:
111 true)` to its call to the superclass's constructor, or by calling
112 `setState(Function fn)`. The former is a way to have a component start its life
113 stateful, and the latter results in the component becoming statefull *as well
114 as* scheduling the component to re-build at the end of the current animation
115 frame.
116
117 What does it mean to be stateful? It means that the diffing mechanism retains
118 the specific *instance* of the component as long as the component which builds
119 it continues to require its presence. The component which constructed it may
120 have provided new configuration in form of different values for the constructor
121 parameters, but these values (public fields) will be copied (using reflection)
122 onto the retained instance whose privates fields are left unmodified.
123
124 Rendering
125 ---------
126
127 At the end of each animation frame, all components (including the root `App`)
128 which have `setState` on themselves will be rebuilt and the resulting changes
129 will be minimally applied to the DOM. Note that components of lower "order"
130 (those near the root of the tree) will build first because their building may
131 require rebuilding of higher order (those near the leaves), thus avoiding the
132 possibility that a component which is dirty build more than once during a single
133 cycle.
134
135 Keys
136 ----
137
138 In order to efficiently apply changes to the DOM and to ensure that stateful
139 components are correctly identified, Effen requires that `no two nodes (except
140 Text) or components of the same type may exist as children of another element
141 without being distinguished by unique keys`. [`Text` is excused from this rule].
142 In many cases, nodes don't require a key because there is only one type amongst
143 its siblings -- but if there is more one, you must assign each a key. This is
144 why most nodes will take `({ Object key })` as an optional constructor
145 parameter. In development mode (i.e. when sky is built `Debug`) Effen will throw
146 an error if you forget to do this.
147
148 Event Handling
149 --------------
150
151 Events logically fire through the Effen node tree. If want to handle an event as
152 it bubbles from the target to the root, create an `EventListenerNode`. `EventLis tenerNode`
153 has named (typed) parameters for a small set of events that we've hit so far, as
154 well as a 'custom' argument which is a `Map<String, sky.EventListener>`. If
155 you'd like to add a type argument for an event, just post a patch.
156
157 ```dart
158 class MyComp extends Component {
159 MyComp({
160 Object key
161 }) : super(key: key);
162
163 void _handleTap(sky.GestureEvent e) {
164 // do stuff
165 }
166
167 void _customEventCallback(sky.Event e) {
168 // do other stuff
169 }
170
171 UINode build() {
172 new EventListenerNode(
173 new Container(
174 children: // ...
175 ),
176 onGestureTap: _handleTap,
177 custom: {
178 'myCustomEvent': _customEventCallback
179 }
180 );
181 }
182
183 _handleScroll(sky.Event e) {
184 setState(() {
185 // update the scroll position
186 });
187 }
188 }
189 ```
190
191 Styling
192 -------
193
194 Styling is the part of Effen which is least designed and is likely to change.
195 There are three ways to specify styles:
196
197 * `Style` objects which are interned and can be applied to WrapperNodes via th e
198 ``style` constructor parameter. Use `Style` objects for styles which are
199 `*not* animated.
200
201 * An `inlineStyle` string which can be applied to Elements via the
202 `inlineStyle` constructor parameter. Use `inlineStyle` for styles which
203 *are* animated.
204
205 If you need to apply a Style to a Component or UINode which you didn't construct
206 (i.e. one that was handed into your constructor), you can wrap it in a
207 `StyleNode` which also takes a `Style` constructor in it's `style` constructor
208 parameter.
209
210 Animation
211 ---------
212
213 Animation is still an area of exploration. Have a look at
214 [AnimatedComponent](components/animated_component.dart) and
215 [Drawer](components/drawer.dart) for an example of this this currently works.
216
217 Performance
218 -----------
219
220 It is a design goal that it should be *possible* to arrange that all "build"
221 cycles which happen during animations can complete in less than one milliesecond
222 on a Nexus 5.
OLDNEW
« no previous file with comments | « sky/sdk/lib/framework/README.md ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698