如何在iOS原生項目中集成react-native項目此處不再贅述。
這里簡單描述如何在iOS原生項目多個地方進入react-native模塊。
或許剛開始在iOS原生項目中集成react-native模塊的時候很開心,集成也很簡單,但是,有一天,增加需求了,需要在另外一個地方增加一個react-native模塊。瞬間懵逼,有木有?如何處理呢?
我們知道,index.ios.js
可以看做是iOS模塊的入口,但是這個入口似乎只有一個,從這個地方入手的話,似乎不太好處理,反正我是放棄治療了。
在網上找了一段時間,沒有找到合適的方法。于是,我決定自己整個方案出來(或許網上有吧??)。在此之前,我在做H5項目的時候,后來將頁面都改成JSP了,里面有個重定向的知識點,由此得到啟發,就有了下面的一個方案。然后呢?于一次異想天開,得出了另一個方案(注冊多個組件)。
兩種方案都用到了RCTRootView
,假設現在需要加載兩個react-native模塊,一個是Discover
,另一個是Profile
。
下面分別說說這兩個方案:
方案一、注冊多個組件
這種方式利用"moduleName"
來實現,具體的玩法是這樣的:
1、在原生項目中的一個地方,
RCTRootView * rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"Discover" initialProperties:props
launchOptions:nil];
在另一處
RCTRootView * rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"Profile" initialProperties:props
launchOptions:nil];
這樣就有了兩個react-native的入口了。組件名也有了。
2、在react-native中的index.ios.js
文件中同時注冊兩個組件作為兩個react-native模塊的入口
AppRegistry.registerComponent('Discover', () => Root1);
AppRegistry.registerComponent('Profile', () => Root2);
采用這種方式的好處是:兩個react-native模塊的代碼相對分離,一個進入組件Root1
,另一個進入Root2
。后面的都是熟悉的玩法了。但是用的node_modules是一套,還是有影響的。
方案二、重定向(重新設置路由)
這種方式利用"initialProperties"
來實現,我們事先傳入react-native模塊路由名,具體的玩法是這樣的:
1、在原生項目中,
NSDictionary *props = @{ @"routeName" : self.routeName };
RCTRootView * rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"MyApp" initialProperties:props
launchOptions:nil];
我們在原生項目中傳入路由名Discover
或Profile
(字符串即可)。
2、在react-native項目中,只要在組件將要加載的時候,修改路由即可。
a)、如果用的是較早的導航Navigator
組件,這樣玩
let initialRoute = null;
export default class App extends Component {
componentWillMount() {
if (this.props.routeName === "Discover") {
initialRoute = Discover;
} else if (this.props.routeName === "Profile") {
initialRoute = Profile;
}
}
render() {
return (
<Navigator
initialRoute={{name: 'initialRouteName', component: initialRoute}}
renderScene={
(route, navigator) => {
_navigator = navigator;
let Component = route.component;
return <Component {...route.params} navigator={navigator}/>
}
}
configureScene={(route) => Navigator.SceneConfigs.HorizontalSwipeJump}
/>
);
}
}
這樣以來,就修改了初始化路由,實現了從不同入口進入react-native模塊。
b)、如果用的Facebook目前推薦的react-navigation組件,玩法是這樣的:
首先,先接收到原生項目傳遞過來的默認屬性值,即routeName,
export default class App extends Component {
render() {
return (
// screenProps 為了傳遞從原生傳遞過來的屬性給項目的initialRoute
<RoutesConfig screenProps={this.props}/>
);
}
}
其次,創建一個組件專門處理初始化路由
class Redirect extends React.Component {
// 重定向到相應的RN模塊
componentWillMount() {
NavigationUtil.reset(this.props.navigation, this.props.screenProps.routeName);
}
render() {
return (
<View />
);
}
}
這里render
一個空白頁,同樣是在componentWillMount() {}
中更改初始化路由。重新設置路由的方法在react-navigation中可以查閱。
最后,將Redirect
組件作為react-navigation組件的初始化路由。
const RoutesConfig = StackNavigator(
{
Redirect: {
screen: Redirect,
},
Discover: {screen: Discover},
Profile: {screen: Profile},
},
{
initialRouteName: 'Redirect', // 默認顯示界面
mode: 'card',
headerMode: 'screen',
cardStyle: {
paddingTop: Platform.OS === 'ios' ? 0 : StatusBar.currentHeight
},
navigationOptions: ({navigation}) => ({
headerStyle: {
backgroundColor: '#48B4EB'
},
headerTitleStyle: {
color: '#fff',
fontSize: 18
},
headerTintColor: '#fff',
}),
}
);
這種方式在一個空白頁處理,雖說是在組件加載之前更改了初始化路由,總歸不好。
到此差不多結束了。然而,感覺這兩種方式都不是很優秀的解決方案,有更好的方式歡迎補充,在此拜謝!