mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Fix: React Native reloads after teardown render a "blank screen" (#38999)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/38999 After React Native tears down, a RedBox can appear, prompting the user to reload. **Problem:** After React Native reloads, the React Native screen wouldn't show up. **Cause:** ReactContext.onHostResume() wasn't executed. Why: - React Native teardown moves the React manager into the **onHostDestroy()** state. - During initialization, React Native only calls ReactContext.onHostResume(), if the React manager was *already* in the **onHostResume()** state. https://www.internalfb.com/code/fbsource/[f82938c7cc9a0ee722c85c33d1027f326049d37c]/xplat/js/react-native-github/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridgeless/ReactHost.java?lines=924-925 **Question:** Why does React Native only call ReactContext.onHostResume(), **if the React manager was already in the onHostResume() state?** In short, we want ReactContext.onHostResume() to be delayed until the user navigates to the first React Native screen. Please read the comments in the code to understand why. ## The fix If we're initializing React Native during a reload, just always call ReactContext.onHostResume(). If React Native is reloading, it seems reasonable to assume that: 1. We must have navigated to a React Native screen in the past, or 2. We must be on a React Native screen. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D48076895 fbshipit-source-id: 6794105920ee30d62cebd745256bb5dea805e891
This commit is contained in:
committed by
Facebook GitHub Bot
parent
ecd2feeea0
commit
75c5d74ea2
+37
-14
@@ -909,29 +909,52 @@ public class ReactHostImpl implements ReactHost {
|
||||
});
|
||||
|
||||
class Result {
|
||||
final ReactInstance mInstance;
|
||||
final ReactContext mContext;
|
||||
|
||||
Result(ReactInstance instance, ReactContext context) {
|
||||
mInstance = instance;
|
||||
mContext = context;
|
||||
}
|
||||
final ReactInstance mInstance = instance;
|
||||
final ReactContext mContext = reactContext;
|
||||
final boolean mIsReloading = mReloadTask != null;
|
||||
}
|
||||
|
||||
return new Result(instance, reactContext);
|
||||
return new Result();
|
||||
},
|
||||
mBGExecutor)
|
||||
.onSuccess(
|
||||
task -> {
|
||||
ReactInstance reactInstance = task.getResult().mInstance;
|
||||
ReactContext reactContext = task.getResult().mContext;
|
||||
final ReactInstance reactInstance = task.getResult().mInstance;
|
||||
final ReactContext reactContext = task.getResult().mContext;
|
||||
final boolean isReloading = task.getResult().mIsReloading;
|
||||
final boolean isManagerResumed =
|
||||
mReactLifecycleStateManager.getLifecycleState() == LifecycleState.RESUMED;
|
||||
|
||||
/**
|
||||
* Call ReactContext.onHostResume() only when already in the resumed state which
|
||||
* aligns with the bridge https://fburl.com/diffusion/2qhxmudv.
|
||||
* ReactContext.onHostResume() should only be called when the user navigates to
|
||||
* the first React Native screen.
|
||||
*
|
||||
* <p>During init: The application puts the React manager in a resumed state,
|
||||
* when the user navigates to a React Native screen. Two types of init: (1) If
|
||||
* React Native init happens when the user navigates to a React Native screen,
|
||||
* the React manager will get resumed on init start, so
|
||||
* ReactContext.onHostResume() will be executed here. (2) If React Native init
|
||||
* happens before the user navigates to a React Native screen (i.e: React Native
|
||||
* is preloaded), the React manager won't be in a resumed state here. So
|
||||
* ReactContext.onHostResume() won't be executed here. But, when the user
|
||||
* navigates to their first React Native screen, the application will call
|
||||
* ReactHost.onHostResume(). That will call ReactContext.onHostResume().
|
||||
*
|
||||
* <p>During reloads, if the manager isn't resumed, call
|
||||
* ReactContext.onHostResume(). If React Native is reloading, it seems
|
||||
* reasonable to assume that: (1) We must have navigated to a React Native
|
||||
* screen in the past, or (2) We must be on a React Native screen.
|
||||
*/
|
||||
mReactLifecycleStateManager.resumeReactContextIfHostResumed(
|
||||
reactContext, mActivity.get());
|
||||
if (isReloading && !isManagerResumed) {
|
||||
mReactLifecycleStateManager.moveToOnHostResume(reactContext, mActivity.get());
|
||||
} else {
|
||||
/**
|
||||
* Call ReactContext.onHostResume() only when already in the resumed state
|
||||
* which aligns with the bridge https://fburl.com/diffusion/2qhxmudv.
|
||||
*/
|
||||
mReactLifecycleStateManager.resumeReactContextIfHostResumed(
|
||||
reactContext, mActivity.get());
|
||||
}
|
||||
|
||||
ReactInstanceEventListener[] listeners =
|
||||
new ReactInstanceEventListener[mReactInstanceEventListeners.size()];
|
||||
|
||||
Reference in New Issue
Block a user