Skip to content

Commit 9d36521

Browse files
authored
Support Context api (wix#4427)
The following PR introduces improved support for Context api and other api's which wrap the root view. ## Context api Navigation.registerComponent('navigation.playground.ContextScreen', () => (props) => ( <TitleContext.Provider value={'Title from Provider'}> <ContextScreen {...props} /> </TitleContext.Provider> ), () => ContextScreen); ## Redux Navigation.registerComponent('navigation.playground.ReduxScreen', () => (props) => ( <Provider store={reduxStore}> <ReduxScreen {...props} /> </Provider> ), () => ReduxScreen); ## Plain Component - not changed Navigation.registerComponent('navigation.playground.MyScreen', () => MyScreen); This PR also upgrades the TypeScript version to 3.2.0 and RN version used in the playground app to 0.57.7 * New Android build flavor - `reactNative57_7` * Unit test coverage is disabled, for some reason it broke after upgrading to RN 0.57.7
1 parent 231e912 commit 9d36521

33 files changed

+501
-163
lines changed

babel.config.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module.exports = function (api) {
2+
api && api.cache(false);
3+
return {
4+
env: {
5+
test: {
6+
presets: [
7+
"module:metro-react-native-babel-preset"
8+
],
9+
plugins: [
10+
"@babel/plugin-proposal-class-properties"
11+
]
12+
}
13+
}
14+
};
15+
}

index.ios.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require('./playground/index');

integration/redux/Redux.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ describe('redux support', () => {
1818
render() {
1919
return (
2020
<Provider store={store.reduxStore}>
21-
<MyConnectedComponent />
21+
<MyConnectedComponent/>
2222
</Provider>
2323
);
2424
}
2525
};
26-
Navigation.registerComponent('ComponentName', () => HOC);
26+
Navigation.registerComponent('ComponentName', () => (props) => <HOC {...props} />, Provider, store.reduxStore);
2727

2828
const tree = renderer.create(<HOC />);
2929
expect(tree.toJSON().children).toEqual(['no name']);
@@ -41,7 +41,7 @@ describe('redux support', () => {
4141
);
4242
}
4343
};
44-
const CompFromNavigation = Navigation.registerComponent('ComponentName', () => HOC)();
44+
const CompFromNavigation = Navigation.registerComponent('ComponentName', () => (props) => <HOC {...props} />)();
4545

4646
const tree = renderer.create(<CompFromNavigation componentId='componentId' renderCountIncrement={renderCountIncrement}/>);
4747
expect(tree.toJSON().children).toEqual(['no name']);

lib/android/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ android {
6464
dimension "RNN.reactNativeVersion"
6565
buildConfigField("int", "REACT_NATVE_VERSION_MINOR", "57")
6666
}
67-
reactNative57WixFork {
67+
reactNative57_5 {
6868
dimension "RNN.reactNativeVersion"
6969
buildConfigField("int", "REACT_NATVE_VERSION_MINOR", "57")
7070
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.reactnativenavigation.react;
2+
3+
import com.facebook.react.bridge.NativeDeltaClient;
4+
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
5+
6+
import javax.annotation.Nullable;
7+
8+
public class DevBundleDownloadListenerAdapter implements DevBundleDownloadListener, NavigationDevBundleDownloadListener {
9+
@Override
10+
public void onSuccess(@Nullable NativeDeltaClient nativeDeltaClient) {
11+
onSuccess();
12+
}
13+
14+
@Override
15+
public void onSuccess() {
16+
17+
}
18+
19+
@Override
20+
public void onProgress(@Nullable String status, @Nullable Integer done, @Nullable Integer total) {
21+
22+
}
23+
24+
@Override
25+
public void onFailure(Exception cause) {
26+
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.reactnativenavigation.react;
2+
3+
import com.facebook.react.bridge.NativeDeltaClient;
4+
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
5+
6+
import javax.annotation.Nullable;
7+
8+
public class JsDevReloadHandlerFacade implements DevBundleDownloadListener, NavigationDevBundleDownloadListener {
9+
@Override
10+
public void onSuccess(@Nullable NativeDeltaClient nativeDeltaClient) {
11+
onSuccess();
12+
}
13+
14+
@Override
15+
public void onProgress(@Nullable String status, @Nullable Integer done, @Nullable Integer total) {
16+
17+
}
18+
19+
@Override
20+
public void onFailure(Exception cause) {
21+
22+
}
23+
24+
@Override
25+
public void onSuccess() {
26+
27+
}
28+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package com.reactnativenavigation.react;
2+
3+
import android.app.Application;
4+
import android.support.annotation.NonNull;
5+
import android.support.annotation.Nullable;
6+
7+
import com.facebook.infer.annotation.Assertions;
8+
import com.facebook.react.ReactInstanceManager;
9+
import com.facebook.react.ReactInstanceManagerBuilder;
10+
import com.facebook.react.ReactNativeHost;
11+
import com.facebook.react.ReactPackage;
12+
import com.facebook.react.common.LifecycleState;
13+
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
14+
import com.facebook.react.shell.MainReactPackage;
15+
import com.reactnativenavigation.NavigationApplication;
16+
17+
import java.util.ArrayList;
18+
import java.util.List;
19+
20+
/**
21+
* Default implementation of {@link ReactNativeHost} that includes {@link NavigationPackage}
22+
* and user-defined additional packages.
23+
*/
24+
public class NavigationReactNativeHost extends ReactNativeHost implements BundleDownloadListenerProvider {
25+
26+
private final boolean isDebug;
27+
private final List<ReactPackage> additionalReactPackages;
28+
private @Nullable NavigationDevBundleDownloadListener bundleListener;
29+
private final DevBundleDownloadListener bundleListenerMediator = new DevBundleDownloadListenerAdapter() {
30+
@Override
31+
public void onSuccess() {
32+
if (bundleListener != null) {
33+
bundleListener.onSuccess();
34+
}
35+
}
36+
};
37+
38+
public NavigationReactNativeHost(NavigationApplication application) {
39+
this(application, application.isDebug(), application.createAdditionalReactPackages());
40+
}
41+
42+
@SuppressWarnings("WeakerAccess")
43+
public NavigationReactNativeHost(Application application, boolean isDebug, final List<ReactPackage> additionalReactPackages) {
44+
super(application);
45+
this.isDebug = isDebug;
46+
this.additionalReactPackages = additionalReactPackages;
47+
}
48+
49+
@Override
50+
public void setBundleLoaderListener(NavigationDevBundleDownloadListener listener) {
51+
bundleListener = listener;
52+
}
53+
54+
@Override
55+
public boolean getUseDeveloperSupport() {
56+
return isDebug;
57+
}
58+
59+
@Override
60+
protected List<ReactPackage> getPackages() {
61+
List<ReactPackage> packages = new ArrayList<>();
62+
boolean hasMainReactPackage = false;
63+
packages.add(new NavigationPackage(this));
64+
if (additionalReactPackages != null) {
65+
for (ReactPackage p : additionalReactPackages) {
66+
if (!(p instanceof NavigationPackage)) {
67+
packages.add(p);
68+
}
69+
if (p instanceof MainReactPackage) hasMainReactPackage = true;
70+
}
71+
}
72+
if (!hasMainReactPackage) {
73+
packages.add(new MainReactPackage());
74+
}
75+
return packages;
76+
}
77+
78+
protected ReactInstanceManager createReactInstanceManager() {
79+
ReactInstanceManagerBuilder builder = ReactInstanceManager.builder()
80+
.setApplication(getApplication())
81+
.setJSMainModulePath(getJSMainModuleName())
82+
.setUseDeveloperSupport(getUseDeveloperSupport())
83+
.setRedBoxHandler(getRedBoxHandler())
84+
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
85+
.setUIImplementationProvider(getUIImplementationProvider())
86+
.setInitialLifecycleState(LifecycleState.BEFORE_CREATE)
87+
.setDevBundleDownloadListener(getDevBundleDownloadListener());
88+
89+
for (ReactPackage reactPackage : getPackages()) {
90+
builder.addPackage(reactPackage);
91+
}
92+
93+
String jsBundleFile = getJSBundleFile();
94+
if (jsBundleFile != null) {
95+
builder.setJSBundleFile(jsBundleFile);
96+
} else {
97+
builder.setBundleAssetName(Assertions.assertNotNull(getBundleAssetName()));
98+
}
99+
return builder.build();
100+
}
101+
102+
@SuppressWarnings("WeakerAccess")
103+
@NonNull
104+
protected DevBundleDownloadListener getDevBundleDownloadListener() {
105+
return bundleListenerMediator;
106+
}
107+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.reactnativenavigation.react;
2+
3+
import com.facebook.react.bridge.NativeDeltaClient;
4+
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
5+
6+
import javax.annotation.Nullable;
7+
8+
public abstract class ReloadHandlerFacade implements DevBundleDownloadListener {
9+
@Override
10+
public void onSuccess(@Nullable NativeDeltaClient nativeDeltaClient) {
11+
12+
}
13+
14+
@Override
15+
public void onProgress(@Nullable String status, @Nullable Integer done, @Nullable Integer total) {
16+
17+
}
18+
19+
@Override
20+
public void onFailure(Exception cause) {
21+
22+
}
23+
24+
protected abstract void onSuccess();
25+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.reactnativenavigation.react;
2+
3+
import android.support.annotation.Nullable;
4+
5+
import com.facebook.react.bridge.ReactApplicationContext;
6+
import com.facebook.react.bridge.ReadableArray;
7+
import com.facebook.react.bridge.ReadableMap;
8+
import com.facebook.react.uimanager.ThemedReactContext;
9+
import com.facebook.react.uimanager.UIImplementation;
10+
import com.facebook.react.uimanager.UIImplementationProvider;
11+
import com.facebook.react.uimanager.UIManagerModule;
12+
import com.facebook.react.uimanager.ViewManager;
13+
import com.facebook.react.uimanager.common.MeasureSpecProvider;
14+
import com.facebook.react.uimanager.common.SizeMonitoringFrameLayout;
15+
import com.facebook.react.uimanager.events.EventDispatcher;
16+
17+
import java.util.List;
18+
19+
@SuppressWarnings("WeakerAccess")
20+
public class SyncUiImplementation extends UIImplementation {
21+
private static final Object lock = new Object();
22+
23+
public static class Provider extends UIImplementationProvider {
24+
@Override
25+
public UIImplementation createUIImplementation(ReactApplicationContext reactContext, List<ViewManager> viewManagerList, EventDispatcher eventDispatcher, int minTimeLeftInFrameForNonBatchedOperationMs) {
26+
return new SyncUiImplementation(reactContext, viewManagerList, eventDispatcher, minTimeLeftInFrameForNonBatchedOperationMs);
27+
}
28+
29+
@Override
30+
public UIImplementation createUIImplementation(ReactApplicationContext reactContext, UIManagerModule.ViewManagerResolver viewManagerResolver, EventDispatcher eventDispatcher, int minTimeLeftInFrameForNonBatchedOperationMs) {
31+
return new SyncUiImplementation(reactContext, viewManagerResolver, eventDispatcher, minTimeLeftInFrameForNonBatchedOperationMs);
32+
}
33+
}
34+
35+
public SyncUiImplementation(ReactApplicationContext reactContext, List<ViewManager> viewManagerList, EventDispatcher eventDispatcher, int minTimeLeftInFrameForNonBatchedOperationMs) {
36+
super(reactContext, viewManagerList, eventDispatcher, minTimeLeftInFrameForNonBatchedOperationMs);
37+
}
38+
39+
public SyncUiImplementation(ReactApplicationContext reactContext, UIManagerModule.ViewManagerResolver viewManagerResolver, EventDispatcher eventDispatcher, int minTimeLeftInFrameForNonBatchedOperationMs) {
40+
super(reactContext, viewManagerResolver, eventDispatcher, minTimeLeftInFrameForNonBatchedOperationMs);
41+
}
42+
43+
@Override
44+
public void manageChildren(
45+
int viewTag,
46+
@Nullable ReadableArray moveFrom,
47+
@Nullable ReadableArray moveTo,
48+
@Nullable ReadableArray addChildTags,
49+
@Nullable ReadableArray addAtIndices,
50+
@Nullable ReadableArray removeFrom) {
51+
synchronized (lock) {
52+
super.manageChildren(viewTag, moveFrom, moveTo, addChildTags, addAtIndices, removeFrom);
53+
}
54+
}
55+
56+
@Override
57+
public void setChildren(int viewTag, ReadableArray childrenTags) {
58+
synchronized (lock) {
59+
super.setChildren(viewTag, childrenTags);
60+
}
61+
}
62+
63+
@Override
64+
public void createView(int tag, String className, int rootViewTag, ReadableMap props) {
65+
synchronized (lock) {
66+
super.createView(tag, className, rootViewTag, props);
67+
}
68+
}
69+
70+
@Override
71+
public void removeRootShadowNode(int rootViewTag) {
72+
synchronized (lock) {
73+
super.removeRootShadowNode(rootViewTag);
74+
}
75+
}
76+
77+
@Override
78+
public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider> void registerRootView(T rootView, int tag, ThemedReactContext context) {
79+
synchronized (lock) {
80+
super.registerRootView(rootView, tag, context);
81+
}
82+
}
83+
}

lib/src/Navigation.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,17 @@ export class NavigationRoot {
3131
private readonly eventsRegistry: EventsRegistry;
3232
private readonly commandsObserver: CommandsObserver;
3333
private readonly componentEventsObserver: ComponentEventsObserver;
34-
private readonly componentWrapper: typeof ComponentWrapper;
34+
private readonly componentWrapper: ComponentWrapper;
3535

3636
constructor() {
3737
this.Element = Element;
3838
this.TouchablePreview = TouchablePreview;
39+
this.componentWrapper = new ComponentWrapper();
3940
this.store = new Store();
40-
this.componentWrapper = ComponentWrapper;
4141
this.nativeEventsReceiver = new NativeEventsReceiver();
4242
this.uniqueIdProvider = new UniqueIdProvider();
4343
this.componentEventsObserver = new ComponentEventsObserver(this.nativeEventsReceiver);
44-
this.componentRegistry = new ComponentRegistry(this.store, this.componentEventsObserver, this.componentWrapper);
44+
this.componentRegistry = new ComponentRegistry(this.store, this.componentEventsObserver);
4545
this.layoutTreeParser = new LayoutTreeParser();
4646
this.layoutTreeCrawler = new LayoutTreeCrawler(this.uniqueIdProvider, this.store);
4747
this.nativeCommandsSender = new NativeCommandsSender();
@@ -56,9 +56,8 @@ export class NavigationRoot {
5656
* Every navigation component in your app must be registered with a unique name.
5757
* The component itself is a traditional React component extending React.Component.
5858
*/
59-
60-
public registerComponent(componentName: string | number, getComponentClassFunc: ComponentProvider): ComponentProvider {
61-
return this.componentRegistry.registerComponent(componentName, getComponentClassFunc);
59+
public registerComponent(componentName: string | number, componentProvider: ComponentProvider, concreteComponentProvider?: ComponentProvider): ComponentProvider {
60+
return this.componentRegistry.registerComponent(componentName, componentProvider, this.componentWrapper, concreteComponentProvider);
6261
}
6362

6463
/**
@@ -71,7 +70,7 @@ export class NavigationRoot {
7170
ReduxProvider: any,
7271
reduxStore: any
7372
): ComponentProvider {
74-
return this.componentRegistry.registerComponent(componentName, getComponentClassFunc, ReduxProvider, reduxStore);
73+
return this.componentRegistry.registerComponent(componentName, getComponentClassFunc, this.componentWrapper, undefined, ReduxProvider, reduxStore);
7574
}
7675

7776
/**

lib/src/adapters/Element.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import * as React from 'react';
22
import * as PropTypes from 'prop-types';
3-
import { View, requireNativeComponent } from 'react-native';
3+
import { requireNativeComponent } from 'react-native';
44

55
let RNNElement: React.ComponentType<any>;
66

77
export class Element extends React.Component<{ elementId: any; resizeMode?: any; }, any> {
88
static propTypes = {
99
elementId: PropTypes.string.isRequired,
10-
resizeMode: PropTypes.string,
11-
...View.propTypes
10+
resizeMode: PropTypes.string
1211
};
1312

1413
static defaultProps = {

0 commit comments

Comments
 (0)