React Native Navbar と React Native Router Flux の使用法を組み合わせて、RN アプリの作成を簡素化しようとしました。そうすることで、ナビゲーターを再度使用する必要があるホームページに到達するまで、React Native Router Fluxを介してルートを切り替えるポイントに到達しました。
その理由は、React Native Router Flux でこのようなものを作成することはまだ可能だとは思わないからです。私がやろうとしているのは、ログイン/サインアップ ページからホーム フィード ページへの簡単なトランジションを作成することです。もちろん、コンポーネントごとに異なるサイド メニューを作成する必要はないので、最初は React Native Starter App Repo で行われていることを模倣しました。しかし、ログイン画面からホーム画面 (基本的に React Native Starter App コード) に遷移しようとすると、次のエラーが発生します。
私のホームページのコードは次のとおりです (これもほとんど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',
},
});
最後に、メインのアプリのルーティング構造は次のようになります。
//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>
);
}
});