Add unstable_deferredUpdates
This is needed to get the triangle demo working.
Andrew Clark committed
Dec 12, 2016 at 13:32 UTC
ead8ab7e2d2a5d318c580675503de761a49745cb
4 files changed
+161
-14
examples/fiber/index.html
+144
-14
@@ -1,5 +1,5 @@
1
<!DOCTYPE html>
2
-<html>
2
+<html style="width: 100%; height: 100%; overflow: hidden">
3
<head>
4
<meta charset="utf-8">
5
<title>Fiber Example</title>
@@ -19,26 +19,156 @@
19
</div>
20
<script src="../../build/react.js"></script>
21
<script src="../../build/react-dom-fiber.js"></script>
22
- <script>
23
- function ExampleApplication(props) {
24
- var elapsed = Math.round(props.elapsed / 100);
25
- var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' );
26
- var message =
27
- 'React has been successfully running for ' + seconds + ' seconds.';
28
-
29
- return React.DOM.p(null, message);
22
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
23
+ <script type="text/babel">
24
+ var dotStyle = {
25
+ position: 'absolute',
26
+ background: '#61dafb',
27
+ font: 'normal 15px sans-serif',
28
+ textAlign: 'center',
29
+ cursor: 'pointer',
30
+ };
31
+
32
+ var containerStyle = {
33
+ position: 'absolute',
34
+ transformOrigin: '0 0',
35
+ left: '50%',
36
+ top: '50%',
37
+ width: '10px',
38
+ height: '10px',
39
+ background: '#eee',
40
+ };
41
+
42
+ var targetSize = 25;
43
+
44
+ class Dot extends React.Component {
45
+ constructor() {
46
+ super();
47
+ this.state = { hover: false };
48
+ }
49
+ enter() {
50
+ this.setState({
51
+ hover: true
52
+ });
53
+ }
54
+ leave() {
55
+ this.setState({
56
+ hover: false
57
+ });
58
+ }
59
+ render() {
60
+ var props = this.props;
61
+ var s = props.size * 1.3;
62
+ var style = {
63
+ ...dotStyle,
64
+ width: s + 'px',
65
+ height: s + 'px',
66
+ left: (props.x) + 'px',
67
+ top: (props.y) + 'px',
68
+ borderRadius: (s / 2) + 'px',
69
+ lineHeight: (s) + 'px',
70
+ background: this.state.hover ? '#ff0' : dotStyle.background
71
+ };
72
+ return (
73
+ <div style={style} onMouseEnter={() => this.enter()} onMouseLeave={() => this.leave()}>
74
+ {this.state.hover ? '*' + props.text + '*' : props.text}
75
+ </div>
76
+ );
77
+ }
78
+ }
79
+
80
+ function SierpinskiTriangle({ x, y, s, children }) {
81
+ if (s <= targetSize) {
82
+ return (
83
+ <Dot
84
+ x={x - (targetSize / 2)}
85
+ y={y - (targetSize / 2)}
86
+ size={targetSize}
87
+ text={children}
88
+ />
89
+ );
90
+ return r;
91
+ }
92
+ var newSize = s / 2;
93
+ var slowDown = false;
94
+ if (slowDown) {
95
+ var e = performance.now() + 0.8;
96
+ while (performance.now() < e) {
97
+ // Artificially long execution time.
98
+ }
99
+ }
100
+
101
+ s /= 2;
102
+
103
+ return [
104
+ <SierpinskiTriangle x={x} y={y - (s / 2)} s={s}>
105
+ {children}
106
+ </SierpinskiTriangle>,
107
+ <SierpinskiTriangle x={x - s} y={y + (s / 2)} s={s}>
108
+ {children}
109
+ </SierpinskiTriangle>,
110
+ <SierpinskiTriangle x={x + s} y={y + (s / 2)} s={s}>
111
+ {children}
112
+ </SierpinskiTriangle>,
113
+ ];
114
}
115
+ SierpinskiTriangle.shouldComponentUpdate = function(oldProps, newProps) {
116
+ var o = oldProps;
117
+ var n = newProps;
118
+ const res = !(
119
+ o.x === n.x &&
120
+ o.y === n.y &&
121
+ o.s === n.s &&
122
+ o.children === n.children
123
+ );
124
+ // console.log('shouldComponentUpdate', res);
125
+ return res;
126
+ };
127
32
- // Call React.createFactory instead of directly call ExampleApplication({...}) in React.render
33
- var ExampleApplicationFactory = React.createFactory(ExampleApplication);
128
+ class ExampleApplication extends React.Component {
129
+ constructor() {
130
+ super();
131
+ this.state = { seconds: 0 };
132
+ this.tick = this.tick.bind(this);
133
+ }
134
+ componentDidMount() {
135
+ this.invervalID = setInterval(this.tick, 1000);
136
+ }
137
+ tick() {
138
+ ReactDOMFiber.unstable_deferredUpdates(() =>
139
+ this.setState(state => ({ seconds: (state.seconds % 10) + 1 }))
140
+ );
141
+ }
142
+ componentWillUnmount() {
143
+ clearInterval(this.intervalID);
144
+ }
145
+ render() {
146
+ const seconds = this.state.seconds;
147
+ const elapsed = this.props.elapsed;
148
+ const t = (elapsed / 1000) % 10;
149
+ const scale = 1 + (t > 5 ? 10 - t : t) / 10;
150
+ const transform = 'scaleX(' + (scale / 2.1) + ') scaleY(0.7) translateZ(0.1px)';
151
+ return (
152
+ <div style={{ ...containerStyle, transform }}>
153
+ <div>
154
+ <SierpinskiTriangle x={0} y={0} s={1000}>
155
+ {this.state.seconds}
156
+ </SierpinskiTriangle>
157
+ </div>
158
+ </div>
159
+ );
160
+ }
161
+ }
162
163
var start = new Date().getTime();
36
- setInterval(function() {
164
+ function update() {
165
ReactDOMFiber.render(
38
- ExampleApplicationFactory({elapsed: new Date().getTime() - start}),
166
+ <ExampleApplication elapsed={new Date().getTime() - start} />,
167
document.getElementById('container')
168
);
41
- }, 50);
169
+ requestAnimationFrame(update);
170
+ }
171
+ requestAnimationFrame(update);
172
</script>
173
</body>
174
</html>
src/renderers/dom/fiber/ReactDOMFiber.js
+2
@@ -242,6 +242,8 @@ var ReactDOM = {
242
243
unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
244
245
+ unstable_deferredUpdates: DOMRenderer.deferredUpdates,
246
+
247
};
248
249
module.exports = ReactDOM;
src/renderers/shared/fiber/ReactFiberReconciler.js
+4
@@ -79,6 +79,7 @@ export type Reconciler<C, I, TI> = {
79
// FIXME: ESLint complains about type parameter
80
batchedUpdates<A>(fn : () => A) : A,
81
syncUpdates<A>(fn : () => A) : A,
82
+ deferredUpdates<A>(fn : () => A) : A,
83
/* eslint-enable no-undef */
84
85
// Used to extract the return value from the initial render. Legacy API.
@@ -103,6 +104,7 @@ module.exports = function<T, P, I, TI, C, CX>(config : HostConfig<T, P, I, TI, C
104
performWithPriority,
105
batchedUpdates,
106
syncUpdates,
107
+ deferredUpdates,
108
} = ReactFiberScheduler(config);
109
110
return {
@@ -195,6 +197,8 @@ module.exports = function<T, P, I, TI, C, CX>(config : HostConfig<T, P, I, TI, C
197
198
syncUpdates,
199
200
+ deferredUpdates,
201
+
202
getPublicRootInstance(container : OpaqueNode) : (ReactComponent<any, any, any> | I | TI | null) {
203
const root : FiberRoot = (container.stateNode : any);
204
const containerFiber = root.current;
src/renderers/shared/fiber/ReactFiberScheduler.js
+11
@@ -1076,11 +1076,22 @@ module.exports = function<T, P, I, TI, C, CX>(config : HostConfig<T, P, I, TI, C
1076
}
1077
}
1078
1079
+ function deferredUpdates<A>(fn : () => A) : A {
1080
+ const previousPriorityContext = priorityContext;
1081
+ priorityContext = LowPriority;
1082
+ try {
1083
+ return fn();
1084
+ } finally {
1085
+ priorityContext = previousPriorityContext;
1086
+ }
1087
+ }
1088
+
1089
return {
1090
scheduleWork: scheduleWork,
1091
getPriorityContext: getPriorityContext,
1092
performWithPriority: performWithPriority,
1093
batchedUpdates: batchedUpdates,
1094
syncUpdates: syncUpdates,
1095
+ deferredUpdates: deferredUpdates,
1096
};
1097
};