-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Does not work well with a few corner cases #8
Comments
Thank you for report! |
I just wanted to mention, in case anyone uses this solution; there is a major bug that can cause 100% CPU usage in the tab after it has been idling for some time. The issue is that For example, this is how a healthy page ticks:
Yet after a very short amount of time, if you switch the tab, this happens:
A fixed version is below. // Based on https://github.com/petehunt/react-raf-batching
// but also triggers `tick` regularly if tab is inactive.
'use strict';
var ReactUpdates = require('react/lib/ReactUpdates'),
requestAnimationFrame = require('./RequestAnimationFrame');
var FORCE_TICK_INTERVAL = 1000;
var flush = ReactUpdates.flushBatchedUpdates.bind(ReactUpdates);
var timeout;
function tick() {
flush();
requestAnimationFrame(tick);
clearTimeout(timeout);
// Do not call `tick()`, that could cause multiple RAF cycles and hog CPU.
timeout = setTimeout(forceTick, FORCE_TICK_INTERVAL);
}
function forceTick() {
flush();
timeout = setTimeout(forceTick, FORCE_TICK_INTERVAL);
}
var ReactRAFBatchingStrategy = {
isBatchingUpdates: true,
/**
* Call the provided function in a context within which calls to `setState`
* and friends are batched such that components aren't updated unnecessarily.
*/
batchedUpdates: function(callback) {
callback.apply(null, Array.prototype.slice.call(arguments, 1));
},
inject: function() {
ReactUpdates.injection.injectBatchingStrategy(ReactRAFBatchingStrategy);
tick();
}
};
module.exports = ReactRAFBatchingStrategy; |
@STRML Thank you for the explanation! |
FYI it appears I actually caused it again! This is a tricky one to avoid. I've updated the example above which I have verified fixes the problem. |
You could also try to leverage the pageVisibility API instead of checking if RAF is properly triggering. This would be a much more performant solution. https://developer.mozilla.org/en-US/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API it has been around for a little while. |
This project isn't maintained, so I'm closing this issue. React internals have changed enough that this repo probably isn't interesting anymore. |
@petehunt Could you elaborate on that? We are still using RAF batching to pretty good effect when large numbers of updates come down the websocket in succession. Is there something else we should be doing instead? |
This was just an Basically, RAF batching was known to cause some issues with controlled form components, and since Facebook wasn't dogfooding it's likely it wouldn't have gotten fixed. My suggestion would be to implement a custom batching strategy for your app based on You could do something like:
Then in your websocket event handler, set Does this make sense? |
Sure - this is what we're using, which ensures updates still fire even if the page isn't visible: // Based on https://github.com/petehunt/react-raf-batching
// but also triggers `tick` regularly if tab is inactive.
let ReactUpdates = require('react/lib/ReactUpdates');
let requestAnimationFrame = require('./RequestAnimationFrame');
let FORCE_TICK_INTERVAL = 1000;
let flush = ReactUpdates.flushBatchedUpdates.bind(ReactUpdates);
let timeout;
function tick() {
flush();
requestAnimationFrame(tick);
clearTimeout(timeout);
// Do not call `tick()`, that could cause multiple RAF cycles and hog CPU.
timeout = setTimeout(forceTick, FORCE_TICK_INTERVAL);
}
function forceTick() {
flush();
timeout = setTimeout(forceTick, FORCE_TICK_INTERVAL);
}
let ReactRAFBatchingStrategy = {
isBatchingUpdates: true,
/**
* Call the provided function in a context within which calls to `setState`
* and friends are batched such that components aren't updated unnecessarily.
*/
batchedUpdates: function(callback: Function) {
// Do we have to do this anymore?
let args = new Array(arguments.length - 1);
for (let i = 0; i < args.length; ++i) {
args[i] = arguments[i + 1];
}
callback.apply(null, args);
},
inject: function() {
ReactUpdates.injection.injectBatchingStrategy(ReactRAFBatchingStrategy);
tick();
}
};
module.exports = ReactRAFBatchingStrategy; What benefit is there to modifying the Also, has the arity of |
@STRML setting Bit of a long day today so I'm not sure if I'm making sense... am I? :) |
Also, looks it still takes up to 5 parameters, and you should call |
Appears that |
Re: the example, that makes sense to prevent unnecessary RAF ticks - thanks. |
@petehunt in your example, it looks like |
I actually like that this strategy enforces async
setState
because it's more deterministic than default strategy in this aspect. Just like Promises resolve on next tick so there's just one code path and not two.We've been using this strategy in production with some success but I'm filing this to warn about a few caveats I found:
<NativeAudio isPlaying>
that wraps HTML5<audio>
and toggleisPlaying
in response to aclick
, RAF batching will delay your call until next frame, and iOS Safari will block it. The solution (if you don't want to give up on RAF batching) is to simply callReactUpdates.flushBatchedUpdates()
aftersetState
inclick
handler.Otherwise it works well for us and we never had problems with controlled inputs that some people were reporting.
The text was updated successfully, but these errors were encountered: