-
Notifications
You must be signed in to change notification settings - Fork 24.3k
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
[Perf] Small delay displaying RCTRootView after a push #1277
Comments
There's an NSNotification called RCTJavaScriptDidLoadNotification that runs once the JS has finished downloading you could listen to. Alternatively you could write a native module that lets JS tell ObjC when your React view has mounted. |
@ide I don't really care about knowing when the JS has finished downloading, because as far as I can tell that when will never be fast enough. What you are suggesting is an interaction like this:
To me, this is unacceptable. A native iOS user would expect there to be no delay between steps 1 and 3. |
I understand you want to improve perceived performance. Two things you could do (separately or together) are:
|
@marcshilling The JS can be preloaded by the bridge in advance of your RCTRootView being displayed. I suggest storing an RCTBridge instance in your app delegate and preloading the JS. You can then create a new RCTRootView on each tap, using the same bridge instance (via |
@nicklockwood's suggestion is really clean and should work well. ++ |
We should probably provide a different template for apps with multiple RCTRootViews. Or maybe just deprecate the RCTRootView convenience constructor that obscures the existence of RCTBridge. |
👍 on @nicklockwood's suggestion as well. I'm using this method in an existing iOS app and it has been working wonderfully for me. I've noticed also that even with this method, there can still be a very slight delay between when the view is pushed and when the content gets rendered. So, in some cases, I'm taking a hybrid approach. Not only do I have the RCTBridge instance in my app delegate, but I also pre-load my RCTRootViews when the calling view loads. Then, when it's time to push the rootView, it's already been loaded and there is no delay at all. Of course, this isn't feasible in all situations (might not work in a UITableView), but it does work. |
@dsibiski - any interest in updating the Embedded App docs to reflect your approach? It seems like you have a good amount of experience with it 😄
Should we spin this off into a separate issue? |
You might be interested in the new |
@nicklockwood Unfortunately the RCTBridge must be initialized on the main thread, if I preload a bridge in my app delegate, it will not only block my app's launch but also consume a lot of memory, any advice about this? |
I'm surprised that RCTBridge blocks your app loading noticably. It's true that it has to be initialized on the main thread, but most of what it does afterwards is done on a background thread. |
You can load the bridge whenever you want, it doesn't have to be at app launch time. For example, you might load it on the screen before you present your RCTRootView controller so that by the time the user presses the button to display the React view, it's already loaded the JS. You could then throw it away again if they go somewhere else in the app. To avoid the additional delay due to the JS app initialization, you could also try pre-creating the RCTRootView off-screen, and then set it as the root of your view controller when it's presented. |
@nicklockwood Thanks for your advice, In my case, the RCTRootView must be preloaded at app launch time, but my app is a pretty large app which is very sensitive about what can be done at launch( RCTBridge's setup method now takes about 500ms, it must be called on main thread, and if the bridge is not initialized, the JS can not be downloaded and loaded.) So I'm looking forward to a setup API which can be called on a background thread completely, for example, it can set up a context which have downloaded and loaded the JS on the background thread , and when I come to main thread, I can initialize a bridge with the context, thus save a lot of time. |
+1 if that makes sense :) |
I'm working on an example repo that will cover more use cases than the one discussed in the docs. There are a couple very simple examples now, but I plan to add more advanced ones very soon. https://github.com/dsibiski/react-native-embedded-app-example I'll also try to work on the 'Embedded Apps' documentation to reflect some of the possible examples. |
I have been looking at your repo and will create some issues soon. One thing I noticed right away is that it's light on comments :) Thank you and I also meant to update this thread with a link to it, but you beat me to it. Marc |
@idibidiart You're right! I'll try to add some comments around the interesting bits. Good call. |
There's also a loadingView you can set on RCTRootView to display a spinner while the React context is initialising. Feel free to reopen this task if you have any other questions about bridge sharing/preloading. |
Let me cut to the chase, I'm trying to load an I have created the bridge in the AppDelegate as @nicklockwood mentioned. I am quickly initializing an RCTRootView when the detail view loads, and then supplying it with constraints to the UITableViewCell. When the API call is finished and I have the data, I send the RCTRootView the appProperties as data. But at this point, the RCTRootView doesn't size to fit properly with the UITableViewCell. I am calling What am I doing wrong? How can the performance be improved here? |
I am attempting to integrate React Native into an existing Objective-C app. My goal is to replace a
UIViewController
's rootUIView
with anRCTRootView
. Following these instructions https://facebook.github.io/react-native/docs/embedded-app.html, I am doing the following inviewDidLoad:
of the view controller:Everything works fine, except that there is a very small (maybe half second) delay between when the view controller is pushed and the React Native view is actually displayed. I tried pre-bundling the javascript but there was no difference. I can only assume this is because the javascript is loaded asynchronously. Is there anyway to guarantee the view is loaded so that it is immediately seen upon a push transition?
The text was updated successfully, but these errors were encountered: