我试图结合使用React Native Navbar& React Native Router Flux简化我的RN应用程序的制作。在这样做的时候,我已经到了一个点,我正在通过React Native Router Flux切换路由,直到我到达主页,我需要再次使用Navigator。
原因在于我不认为可以使用React Native Router Flux创建类似this的内容。我要做的是创建一个从登录/注册页面到主菜单页面的简单过渡,这些页面在侧面菜单之间导航。当然,您不希望在每个组件上创建不同的侧面菜单,因此我模仿了React Native Starter应用程序Repo中的操作。但是当我尝试从登录屏幕转换到主屏幕(本质上是React Native Starter应用程序代码)时,我收到以下错误:
我的主页代码如下(同样来自React Native Starter App):
//user home feed with personalized news based
//on onboarding experience
'use strict';
//component variables
var React = require('react-native');
var { Component, StyleSheet, Navigator, Text, View } = React;
var EventEmitter = require('EventEmitter');
var Subscribable = require('Subscribable');
//libraries
var NavigationBar = require('react-native-navbar');
var SideMenu = require('react-native-side-menu');
// App Globals
var AppStyles = require('../styles/styles');
// Components
var Icons = require('../components/icons');
var Menu = require('../components/menu');
// Screens / Pages
var Index = require('../screens/soon');
/* ==============================
Main Navigator with Sidemenu
=============================== */
module.exports = React.createClass({
mixins: [Subscribable.Mixin],
//before application load
getInitialState: function() {
return {
touchToClose: true,
disableGestures: false,
};
},
//on application load
componentWillMount: function() {
this.eventEmitter = new EventEmitter();
},
//When Back Button from NavBar is Clicked
onLeftBackButtonPress: function(navigator) {
this.refs.rootNavigator.pop();
},
//When Hamburger from NavBar is Clicked
onLeftButtonPress: function() {
this.eventEmitter.emit('toggleMenu');
},
//Navigates to page from menu
navigate: function(title, link) {
this.refs.rootSidebarMenu.closeMenu();
this.refs.rootNavigator.replace({
title: title,
component: link,
});
},
//Generate Custom Navbar
renderScene: function(route, navigator) {
var Component = route.component;
var navBar = route.navigationBar;
// Icons
var MenuIcon = Icons.MenuIcon;
var BackIcon = Icons.BackIcon;
// Navbar Setup
if (navBar) {
navBar = React.addons.cloneWithProps(navBar, {
navigator: navigator,
route: route
});
}
// Determine which Icon component - hamburger or back?
var customPrev = <MenuIcon leftButtonPress={this.onLeftButtonPress} />;
if (route.index > 0){
var customPrev = <BackIcon leftButtonPress={this.onLeftBackButtonPress} />;
}
// Done
return (
<View style={AppStyles.container}>
<NavigationBar
style={AppStyles.navbar}
customPrev={customPrev} />
<Component navigator={navigator} route={route} />
</View>
);
},
/**
* RENDER
*/
render: function() {
return (
<SideMenu
ref="rootSidebarMenu"
menu={<Menu events={this.eventEmitter} navigate={this.navigate} />}
touchToClose={this.state.touchToClose}
disableGestures={this.state.disableGestures}>
<Navigator
ref="rootNavigator"
style={[AppStyles.container, AppStyles.appContainer]}
renderScene={this.renderScene}
initialRoute={{
component: Index,
index: 0,
}} />
</SideMenu>
);
}
});
/* ==============================
Styles
=============================== */
var styles = StyleSheet.create({
});
推送到主页路由的代码如下所示:
//component that opens up app to login screen
var React = require('react-native');
var {
View,
Text,
StyleSheet,
Image,
TextInput,
} = React;
//additional libraries
var Parse = require('parse/react-native');
var ParseReact = require('parse-react/react-native');
var FBLoginManager = require('NativeModules').FBLoginManager;
var FBSDKCore = require('react-native-fbsdkcore');
var Actions = require('react-native-router-flux').Actions;
var { FBSDKGraphRequest, FBSDKGraphRequestManager } = FBSDKCore;
//dimensions
var Dimensions = require('Dimensions');
var window = Dimensions.get('window');
//dynamic variable components
var ImageButton = require('../components/imageButton');
module.exports = React.createClass({
componentWillMount: function(){
},
getInitialState: function() {
return {
username: '',
password: '',
errorMessage: '',
loadingCurrentUser: true,
};
},
render: function() {
return (
<View style={[styles.container]}>
<Image
style={styles.bg}
source={require('../img/login_bg1_3x.png')}>
<View style={[styles.header, this.border('red')]} >
<View style={styles.headerWrapper} >
<Image
style={[styles.login_brand]}
resizeMode={"contain"}
source={require('../img/login_brand_2.png')} />
<ImageButton
style={[styles.fb_btn]}
resizeMode={'contain'}
onPress={this.onFbLoginPress}
source={require('../img/fb_login.png')} />
<Image
style={[styles.loginBar]}
style={[styles.loginBar]}
resizeMode={'contain'}
source={require('../img/login_bar_3x.png')} />
</View>
</View>
<View style={[styles.footer, this.border('blue')]} >
<View style={styles.footerWrapper} >
<Text style={styles.error}>{this.state.errorMessage}</Text>
<TextInput
placeholder={'Email'}
style={styles.input}
value={this.state.username}
onChangeText={(text) => this.setState({username: text})} />
<TextInput
placeholder={'Password'}
style={styles.input}
secureTextEntry={true}
value={this.state.password}
onChangeText={(text) => this.setState({password: text})} />
<ImageButton
style={[styles.email_btn]}
resizeMode={'contain'}
onPress={this.onEmailLoginPress}
source={require('../img/email_login_btn.png')} />
<ImageButton
style={[styles.email_btn]}
resizeMode={'contain'}
onPress={Actions.pop}
source={require('../img/create_acct_btn.png')} />
</View>
</View>
</Image>
</View>
);
},
onFbLoginPress: function() {
},
onEmailLoginPress: function() {
//log the user on, get eror if login information doesn't exist
//we need to show the user that the error occured
Parse.User.logIn(this.state.username, this.state.password, {
success: (user) => {
Actions.home();
console.log("Successful Login!");
},
error: (data, error) => { this.setState({ errorMessage: error.message }); }
});
},
//function that helps with laying out flexbox itmes
//takes a color argument to construct border, this is an additional
//style because we dont want to mess up our real styling
border: function(color) {
return {
//borderColor: color,
//borderWidth: 4,
}
},
});
var styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'stretch',
},
bg: {
flex: 1,
width: window.width,
height: window.height,
},
header: {
flex: 2,
},
headerWrapper: {
flex: 1,
flexDirection: 'column',
alignItems: 'center',
justifyContent:'space-around',
marginTop: window.height/35,
},
footerWrapper: {
flexDirection: 'column',
alignItems: 'center',
justifyContent:'space-around',
marginTop: 15,
},
footer: {
flex: 4,
},
loginBar: {
width: (window.width/1.3)/1.8,
height: (70/553)*((window.width/1.3)/1.8),
},
fb_btn: {
width: window.width/1.3,
height: (147/1095)*window.width/1.3,
margin: 10,
},
login_brand: {
width: window.width/6,
height: (268/273)*window.width/6,
margin: 6,
},
input: {
padding: 4, //gives us offset to border
height: window.height/20,
backgroundColor: 'rgba(255,255,255, 0.4)',
borderColor: 'gray',
borderWidth: 1,
borderRadius: 2, //round input box
margin: 2,
width: window.width/1.3,
alignSelf: 'center', //center yourself on form when you have fixed widths
},
email_btn: {
width: window.width/1.3,
height: (147/1095)*window.width/1.3,
margin: 3,
},
error: {
alignItems: 'center',
alignSelf:'center',
fontFamily: 'Bebas Neue',
fontSize: 15,
color:'red',
},
});
最后,我在app中的应用程序的路由结构如下所示:
//routing component to connect
//android and ios to same build
'use strict';
//component variables
var React = require('react-native');
var { Text, View, StyleSheet, Navigator} = React;
var Launch = require('./src/screens/launch');
var Signup = require('./src/screens/signup');
var Signin = require('./src/screens/signin');
var Introduction = require('./src/screens/introduction');
var Home = require('./src/screens/home');
//dynamic libraries
var SplashScreen = require('@remobile/react-native-splashscreen');
var Parse = require('parse/react-native');
var {Router, Route, Schema, Animations, TabBar} = require('react-native-router-flux');
module.exports = React.createClass({
componentWillMount: function() {
//executed when component shows on screen
//tells app to initialize parse and facebook js sdk
Parse.initialize("???", "???");
},
componentDidMount: function() {
SplashScreen.hide();
},
render: function() {
return (
<Router hideNavBar={true} initialRoutes={['launch']}>
<Schema name="bottom" sceneConfig={Navigator.SceneConfigs.FloatFromBottom}/>
<Schema name="right" sceneConfig={Navigator.SceneConfigs.FloatFromRight}/>
<Schema name="withoutAnimation"/>
<Route name="launch" component={Launch} wrapRouter={true} title="Launch" hideNavBar={true} schema="right"/>
<Route name="signin" component={Signin} title="Signin" schema="right"/>
<Route name="signup" component={Signup} title="Signup" schema="right"/>
<Route name="introduction" component={Introduction} title="Introduction" schema="right"/>
<Route name="home" component={Home} title="Home" schema="right"/>
</Router>
);
}
});