@samitouri / QOS-React / commits / ead8ab7e2d

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 };