mirror of
https://github.com/facebook/react.git
synced 2026-02-26 02:25:04 +00:00
I introduce the ReactDOMFrameScheduling module which just exposes rIC and rAF. The polyfill works by scheduling a requestAnimationFrame, store the time for the start of the frame, then schedule a postMessage which gets scheduled after paint. The deadline is set to time + frame rate. By separating the idle call into a separate event tick we ensure that layout, paint and other browser work is counted against the available time. The frame rate is dynamically adjusted by tracking the minimum time between two rAF callbacks. This is not perfect because browsers can schedule multiple callbacks to catch up after a long frame. To compensate for this we only adjust if two consecutive periods are faster than normal. This seems to guarantee that we will hit frame deadlines and we don't end up dropping frames. However, there is still some lost time so we risk starving by not having enough idle time. Especially Firefox seems to have issues keeping up on the triangle demo However, that is also true for native rIC in Firefox. It seems like more render work is scheduled on the main thread pipeline and also that JS execution just generally has more overhead.
173 lines
4.9 KiB
HTML
173 lines
4.9 KiB
HTML
<!DOCTYPE html>
|
|
<html style="width: 100%; height: 100%; overflow: hidden">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Fiber Example</title>
|
|
<link rel="stylesheet" href="../shared/css/base.css" />
|
|
</head>
|
|
<body>
|
|
<h1>Fiber Example</h1>
|
|
<div id="container">
|
|
<p>
|
|
To install React, follow the instructions on
|
|
<a href="https://github.com/facebook/react/">GitHub</a>.
|
|
</p>
|
|
<p>
|
|
If you can see this, React is <strong>not</strong> working right.
|
|
If you checked out the source from GitHub make sure to run <code>grunt</code>.
|
|
</p>
|
|
</div>
|
|
<script src="../../build/react.js"></script>
|
|
<script src="../../build/react-dom-fiber.js"></script>
|
|
<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',
|
|
};
|
|
|
|
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>
|
|
);
|
|
}
|
|
}
|
|
|
|
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 = true;
|
|
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;
|
|
return !(
|
|
o.x === n.x &&
|
|
o.y === n.y &&
|
|
o.s === n.s &&
|
|
o.children === n.children
|
|
);
|
|
};
|
|
|
|
class ExampleApplication extends React.Component {
|
|
constructor() {
|
|
super();
|
|
this.state = { seconds: 0 };
|
|
this.tick = this.tick.bind(this);
|
|
}
|
|
componentDidMount() {
|
|
this.intervalID = 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();
|
|
function update() {
|
|
ReactDOMFiber.render(
|
|
<ExampleApplication elapsed={new Date().getTime() - start} />,
|
|
document.getElementById('container')
|
|
);
|
|
requestAnimationFrame(update);
|
|
}
|
|
requestAnimationFrame(update);
|
|
</script>
|
|
</body>
|
|
</html>
|