Add unstable_deferredUpdates

This is needed to get the triangle demo working.
This commit is contained in:
Andrew Clark 2016-12-12 13:32:00 -08:00
parent 20f00045d3
commit ead8ab7e2d
4 changed files with 160 additions and 13 deletions

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html style="width: 100%; height: 100%; overflow: hidden">
<head>
<meta charset="utf-8">
<title>Fiber Example</title>
@ -19,26 +19,156 @@
</div>
<script src="../../build/react.js"></script>
<script src="../../build/react-dom-fiber.js"></script>
<script>
function ExampleApplication(props) {
var elapsed = Math.round(props.elapsed / 100);
var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' );
var message =
'React has been successfully running for ' + seconds + ' seconds.';
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
<script type="text/babel">
var dotStyle = {
position: 'absolute',
background: '#61dafb',
font: 'normal 15px sans-serif',
textAlign: 'center',
cursor: 'pointer',
};
return React.DOM.p(null, message);
var containerStyle = {
position: 'absolute',
transformOrigin: '0 0',
left: '50%',
top: '50%',
width: '10px',
height: '10px',
background: '#eee',
};
var targetSize = 25;
class Dot extends React.Component {
constructor() {
super();
this.state = { hover: false };
}
enter() {
this.setState({
hover: true
});
}
leave() {
this.setState({
hover: false
});
}
render() {
var props = this.props;
var s = props.size * 1.3;
var style = {
...dotStyle,
width: s + 'px',
height: s + 'px',
left: (props.x) + 'px',
top: (props.y) + 'px',
borderRadius: (s / 2) + 'px',
lineHeight: (s) + 'px',
background: this.state.hover ? '#ff0' : dotStyle.background
};
return (
<div style={style} onMouseEnter={() => this.enter()} onMouseLeave={() => this.leave()}>
{this.state.hover ? '*' + props.text + '*' : props.text}
</div>
);
}
}
// Call React.createFactory instead of directly call ExampleApplication({...}) in React.render
var ExampleApplicationFactory = React.createFactory(ExampleApplication);
function SierpinskiTriangle({ x, y, s, children }) {
if (s <= targetSize) {
return (
<Dot
x={x - (targetSize / 2)}
y={y - (targetSize / 2)}
size={targetSize}
text={children}
/>
);
return r;
}
var newSize = s / 2;
var slowDown = false;
if (slowDown) {
var e = performance.now() + 0.8;
while (performance.now() < e) {
// Artificially long execution time.
}
}
s /= 2;
return [
<SierpinskiTriangle x={x} y={y - (s / 2)} s={s}>
{children}
</SierpinskiTriangle>,
<SierpinskiTriangle x={x - s} y={y + (s / 2)} s={s}>
{children}
</SierpinskiTriangle>,
<SierpinskiTriangle x={x + s} y={y + (s / 2)} s={s}>
{children}
</SierpinskiTriangle>,
];
}
SierpinskiTriangle.shouldComponentUpdate = function(oldProps, newProps) {
var o = oldProps;
var n = newProps;
const res = !(
o.x === n.x &&
o.y === n.y &&
o.s === n.s &&
o.children === n.children
);
// console.log('shouldComponentUpdate', res);
return res;
};
class ExampleApplication extends React.Component {
constructor() {
super();
this.state = { seconds: 0 };
this.tick = this.tick.bind(this);
}
componentDidMount() {
this.invervalID = setInterval(this.tick, 1000);
}
tick() {
ReactDOMFiber.unstable_deferredUpdates(() =>
this.setState(state => ({ seconds: (state.seconds % 10) + 1 }))
);
}
componentWillUnmount() {
clearInterval(this.intervalID);
}
render() {
const seconds = this.state.seconds;
const elapsed = this.props.elapsed;
const t = (elapsed / 1000) % 10;
const scale = 1 + (t > 5 ? 10 - t : t) / 10;
const transform = 'scaleX(' + (scale / 2.1) + ') scaleY(0.7) translateZ(0.1px)';
return (
<div style={{ ...containerStyle, transform }}>
<div>
<SierpinskiTriangle x={0} y={0} s={1000}>
{this.state.seconds}
</SierpinskiTriangle>
</div>
</div>
);
}
}
var start = new Date().getTime();
setInterval(function() {
function update() {
ReactDOMFiber.render(
ExampleApplicationFactory({elapsed: new Date().getTime() - start}),
<ExampleApplication elapsed={new Date().getTime() - start} />,
document.getElementById('container')
);
}, 50);
requestAnimationFrame(update);
}
requestAnimationFrame(update);
</script>
</body>
</html>

View File

@ -242,6 +242,8 @@ var ReactDOM = {
unstable_batchedUpdates: ReactGenericBatching.batchedUpdates,
unstable_deferredUpdates: DOMRenderer.deferredUpdates,
};
module.exports = ReactDOM;

View File

@ -79,6 +79,7 @@ export type Reconciler<C, I, TI> = {
// FIXME: ESLint complains about type parameter
batchedUpdates<A>(fn : () => A) : A,
syncUpdates<A>(fn : () => A) : A,
deferredUpdates<A>(fn : () => A) : A,
/* eslint-enable no-undef */
// 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
performWithPriority,
batchedUpdates,
syncUpdates,
deferredUpdates,
} = ReactFiberScheduler(config);
return {
@ -195,6 +197,8 @@ module.exports = function<T, P, I, TI, C, CX>(config : HostConfig<T, P, I, TI, C
syncUpdates,
deferredUpdates,
getPublicRootInstance(container : OpaqueNode) : (ReactComponent<any, any, any> | I | TI | null) {
const root : FiberRoot = (container.stateNode : any);
const containerFiber = root.current;

View File

@ -1076,11 +1076,22 @@ module.exports = function<T, P, I, TI, C, CX>(config : HostConfig<T, P, I, TI, C
}
}
function deferredUpdates<A>(fn : () => A) : A {
const previousPriorityContext = priorityContext;
priorityContext = LowPriority;
try {
return fn();
} finally {
priorityContext = previousPriorityContext;
}
}
return {
scheduleWork: scheduleWork,
getPriorityContext: getPriorityContext,
performWithPriority: performWithPriority,
batchedUpdates: batchedUpdates,
syncUpdates: syncUpdates,
deferredUpdates: deferredUpdates,
};
};