Adding menu button for Navigation drawer gives error - react-native

I've searched how to setup a button to make the drawer action on Stackoverflow for my react-native project and followed as per answers, but still it is not working. Some answers, it simply didn't work, but sometimes it is giving error (Invariant violation error). But the sliding action for opening up the drawer is working, still I want to include button for navigation drawer. I referred this link : Add hamburger button to React Native Navigation
Here is my code, I'm sorry it is too large.
import React, { Component } from 'react';
import {
StyleSheet, Text,
View, TextInput,
Button, TouchableHighlight,
TouchableOpacity, Image,
Alert, ImageBackground,
Platform, YellowBox,
Dimensions, Keyboard,
TouchableWithoutFeedback, AsyncStorage,
ActivityIndicator, FlatList,
ScrollView
} from 'react-native';
import { createStackNavigator, createAppContainer,createDrawerNavigator, DrawerToggle, DrawerNavigator, DrawerActions, StackNavigator } from "react-navigation";
import { Container, Content, ListItem, List } from "native-base";
class Hidden extends React.Component {
render() {
return null;
}
}
const DismissKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
{children}
</TouchableWithoutFeedback>
);
class LoginView extends Component {
static navigationOptions = {
header: null,
};
constructor(props) {
super(props);
this.myTextInput1 = React.createRef();
this.myTextInput2 = React.createRef();
this.state = {
email : '',
password: '',
};
let keys = ['email', 'password'];
AsyncStorage.multiRemove(keys, (err) => {
console.log('Local storage user info removed!');
});
}
onClickListener = (viewId) => {
Alert.alert("Help", "Contact Admin for "+viewId);
}
validateEmail = (email) => {
var re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
};
loginNext = ()=>{
AsyncStorage.multiSet([
["email", this.state.email],
["password", this.state.password]
]);
this.setState({
email : '',
password: '',
});
this.myTextInput1.current.clear();
this.myTextInput2.current.clear();
Keyboard.dismiss();
if (this.validateEmail(this.state.email)){
this.props.navigation.navigate('profile');
}
else{
Alert.alert('Warning','Enter proper email!')
}
}
render() {
return (
<DismissKeyboard>
<ImageBackground source={require('./zbg_app_1.jpg')} style={{width: '100%', height: '100%'}}>
<View style={styles.container}>
<View style={styles.inputContainer}>
<Image style={styles.inputIcon} source={{uri: 'https://png.icons8.com/email/ultraviolet/50/3498db'}}/>
<TextInput style={styles.inputs}
placeholder="Email"
keyboardType="email-address"
underlineColorAndroid='transparent'
onChangeText={(email) => this.setState({email})}
ref = {this.myTextInput1}/>
</View>
<View style={styles.inputContainer}>
<Image style={styles.inputIcon} source={{uri: 'https://png.icons8.com/key-2/ultraviolet/50/3498db'}}/>
<TextInput style={styles.inputs}
placeholder="Password"
secureTextEntry={true}
underlineColorAndroid='transparent'
onChangeText={(password) => this.setState({password})}
ref = {this.myTextInput2}/>
</View>
<TouchableHighlight style={[styles.buttonContainer, styles.loginButton]} onPress={()=>{(this.state.email != '' && this.state.password != '') ?this.loginNext():Alert.alert('Warning','Empty Field(s)!')}}>
<Text style={styles.loginText}>Login</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.buttonContainer} onPress={() => this.onClickListener('forgot_password')}>
<Text>Forgot your password?</Text>
</TouchableHighlight>
</View>
</ImageBackground>
</DismissKeyboard>
);
}
}
class ProfileView extends Component {
static navigationOptions = {
headerTitle: 'Profile',
};
constructor(props) {
super(props);
this.myTextInput1 = React.createRef();
this.state = {
loggedEmail :'',
loggedPassword: '',
city:''
}
}
submitNext = ()=>{
this.myTextInput1.current.clear();
Keyboard.dismiss();
Alert.alert('Information',this.state.city);
{/*AsyncStorage.setItem('city',this.state.city);
this.setState({
city:''
});
*/}
}
render() {
AsyncStorage.multiGet(['email', 'password']).then(data => {
let email = data[0][1];
let password = data[1][1];
if (email !== null){
this.setState({loggedEmail:email});
}
});
return (
<View style={{ flexDirection: 'column' , alignItems: 'center', justifyContent: 'center'}}>
<View style={{ flexDirection: 'column' , marginTop: 60, alignItems: 'center', justifyContent: 'center'}}>
<Text>{this.state.loggedEmail}</Text>
<Button onPress={()=> this.props.navigation.navigate('login')} title="Login Page"/>
</View>
{/*<View style={styles.container1}>
<View style={styles.inputContainer}>
<TextInput style={styles.inputs}
placeholder="Enter city"
underlineColorAndroid='transparent'
onChangeText={(city) => this.setState({city})}
ref = {this.myTextInput1}/>
</View>
<TouchableHighlight style={[styles.buttonContainer, styles.loginButton]} onPress={()=>{(this.state.city != '') ?this.submitNext():Alert.alert('Warning','Empty Field(s)!')}}>
<Text style={styles.loginText}>Submit</Text>
</TouchableHighlight>
</View>*/}
</View>
);
}
}
class Custom_Side_Menu extends Component {
render() {
return (
<View style={styles.sideMenuContainer}>
<Image source={{ uri: 'https://reactnativecode.com/wp-content/uploads/2017/10/Guitar.jpg' }}
style={styles.sideMenuProfileIcon} />
<View style={{ width: '100%', height: 1, backgroundColor: '#e2e2e2', marginTop: 15}} />
<View style={{width: '100%'}}>
<View style={{flexDirection: 'row', alignItems: 'center', marginTop: 10}}>
<Image source={{ uri: 'https://reactnativecode.com/wp-content/uploads/2018/08/social.jpg' }}
style={styles.sideMenuIcon} />
<Text style={styles.menuText} onPress={() => { this.props.navigation.navigate('First') }} > First Activity </Text>
</View>
<View style={{flexDirection: 'row', alignItems: 'center', marginTop: 10}}>
<Image source={{ uri: 'https://reactnativecode.com/wp-content/uploads/2018/08/promotions.jpg' }}
style={styles.sideMenuIcon} />
<Text style={styles.menuText} onPress={() => { this.props.navigation.navigate('Second') }} > Second Activity </Text>
</View>
<View style={{flexDirection: 'row', alignItems: 'center', marginTop: 10}}>
<Image source={{ uri: 'https://reactnativecode.com/wp-content/uploads/2018/08/outbox.jpg' }}
style={styles.sideMenuIcon} />
<Text style={styles.menuText} onPress={() => { this.props.navigation.navigate('Third') }} > Third Activity </Text>
</View>
</View>
<View style={{ width: '100%', height: 1, backgroundColor: '#e2e2e2', marginTop: 15}} />
</View>
);
}
}
class Fetch extends Component{
constructor(props){
super(props);
this.state ={ isLoading: true,};
}
componentDidMount(){
return fetch('http://d4abf7d9.ngrok.io/opdytat003/api/login/',
{
method: 'POST',
headers:{
Accept: 'application/json',
'Content-Type': 'application/json',
},
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render(){
console.log(this.state.dataSource)
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return(
<ScrollView style={{flex: 1, paddingTop:30}}>
{/*<FlatList
data={this.state.dataSource}
renderItem={({item}) => <Text>{item.title}, {item.releaseYear}</Text>}
keyExtractor={({id}, index) => id}
/>*/}
<Text>API => Zelthy API:</Text>
<Text>{JSON.stringify(this.state.dataSource.next_step)}</Text>
<Text>{JSON.stringify(this.state.dataSource.access_token)}</Text>
<Text>{JSON.stringify(this.state.dataSource.menu)}</Text>
<Text>{JSON.stringify(this.state.dataSource.detail)}</Text>
<Text>{JSON.stringify(this.state.dataSource.responsecode)}</Text>
<Text>{JSON.stringify(this.state.dataSource.refresh_token)}</Text>
</ScrollView>
);
}
}
const AppLogin = createStackNavigator({
login: {
screen: LoginView,
},
},
{
initialRouteName: "login"
}
);
const AppProfile = createStackNavigator({
profile: {
screen: ProfileView,
},
},
);
const Nav = createDrawerNavigator(
{
Home: {
screen: AppLogin,
navigationOptions:{
drawerLockMode: 'locked-closed',
drawerLabel: <Hidden />
},
},
Profile: {
screen: AppProfile
},
Activities: {screen: Custom_Side_Menu},
API: {screen: Fetch},
'Sign Out': {screen: LoginView},
},
{
contentOptions: {
activeTintColor: 'green',
inactiveTintColor: 'white',
},
drawerPosition: 'left',
drawerWidth: 200,
drawerBackgroundColor: 'purple',
initialRouteName: 'Home'
}
);
export default createAppContainer(Nav);
I've referred Github React Native issues links but it also didn't help in my case.
When I add this part of code in StackNavigator of Profile screen, I get this below output but no change on clicking.
navigationOptions: ({ navigation }) => ({
title: 'Profile', // Title to appear in status bar
headerLeft: <Button title='=' onPress={ () => navigation.navigate('DrawerOpen') } />
})
Screenshot:

https://reactnavigation.org/docs/en/drawer-navigator.html#drawernavigatorconfig
Add contentComponent in DrawerNavigatorConfig which displays actual side MenuBar and put hamburger on top-left of MenuBar if it slides from right and on top-right of MenuBar is it slides from left side of screen.
contentComponent is basically React Component, where you display list of items like Home, Profile, My orders, Logout etc, You can add your hamburger above all this options, somewhere in top corners.
In addition, Try replacing Button with TouchableOpacity. Also, first of all try logging something on console with onPress function of TouchableOpacity. If it is logging successfully only then attach navigation.navigate("xyz-screen"), also make sure that your navigation object has navigate method present in it. Sometimes this gives error because of undefined navigation object. If navigation object exist, the try using onPress = {navigation.openDrawer} instead of navigation.navigate("DrawerOpen").

Related

ReactNative issue with contructor saying ';' error

This is my code want to implement an add country and region drop down. I am facing and error at 7,8 line saying semicolon is missing. I would like help as i am beginner at reactnative.
import React,{ Component } from 'react';
import { CountryDropdown, RegionDropdown } from 'react-country-region-selector';
import { StyleSheet, Text, TextInput, View } from 'react-native';
export default function App extends Component() {
constructor(props) {
super(props);
this.state = { country: '', region: '' };
};
selectCountry=(val)=>{
this.setState({ country: val });
};
selectRegion=(val)=>{
this.setState({ region: val });
};
const { country, region } = this.state;
return (
<View style={styles.container}>
<View style={styles.line}>
<Text style={styles.text}>Enter name:</Text>
<TextInput
style={styles.input}
placeholder='e.g. John Doe'
/>
</View>
<View style={styles.line}>
<Text style={styles.text}>Enter Age:</Text>
<TextInput
keyboardType='numeric'
style={styles.input}
placeholder='2'
/>
</View>
<View style={styles.line}>
<Text style={styles.text}>Enter Country:</Text>
<CountryDropdown
value={country}
onValueChange={(val) => this.selectCountry(val)} />
</View>
<View style={styles.line}>
<Text style={styles.text}>Enter Region:</Text>
<RegionDropdown
country={country}
value={region}
onValueChange={(val) => this.selectRegion(val)} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex:1,
backgroundColor: '#fff',
alignItems:'center',
justifyContent:'center',
},
line:{
flexDirection:'row',
flex:0,
marginBottom:5,
},
text:{
flex:1,
},
input:{
flex:1,
width:70,
borderBottomWidth:1,
borderBottomColor:'#777',
},
});
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
You are using a class component but calling it a function ....
change export default function App extends Component() { to export default class App extends Component(){
also add a render() function with appropriate surrounding brackets
new code below
import React,{ Component } from 'react';
import { CountryDropdown, RegionDropdown } from 'react-country-region-selector';
import { StyleSheet, Text, TextInput, View } from 'react-native';
export default class App extends Component() { <-- change here
constructor(props) {
super(props);
this.state = { country: '', region: '' };
};
selectCountry=(val)=>{
this.setState({ country: val });
};
selectRegion=(val)=>{
this.setState({ region: val });
};
render() { <-- add here
const {country, region} = this.state;
return (
<View style={styles.container}>
<View style={styles.line}>
<Text style={styles.text}>Enter name:</Text>
<TextInput
style={styles.input}
placeholder='e.g. John Doe'
/>
</View>
<View style={styles.line}>
<Text style={styles.text}>Enter Age:</Text>
<TextInput
keyboardType='numeric'
style={styles.input}
placeholder='2'
/>
</View>
<View style={styles.line}>
<Text style={styles.text}>Enter Country:</Text>
<CountryDropdown
value={country}
onValueChange={(val) => this.selectCountry(val)}/>
</View>
<View style={styles.line}>
<Text style={styles.text}>Enter Region:</Text>
<RegionDropdown
country={country}
value={region}
onValueChange={(val) => this.selectRegion(val)}/>
</View>
</View>
);
} <-- add here
}
const styles = StyleSheet.create({
container: {
flex:1,
backgroundColor: '#fff',
alignItems:'center',
justifyContent:'center',
},
line:{
flexDirection:'row',
flex:0,
marginBottom:5,
},
text:{
flex:1,
},
input:{
flex:1,
width:70,
borderBottomWidth:1,
borderBottomColor:'#777',
},
});

React component not re-rendering on state change using setState

I have a HomeScreen component which has button. I am trying to popup a modelview(Seperate component ie PopUpView) on the button click. In PopUpView i am sending its visibility as prop (isVisible).On the click of the button i am trying to change the state value popUpIsVisible from false to true. Hoping that this would re-render and popup my model view(Note this is working fine if i explicitly pass true). However with the state change it look like the render function is not being called and the popUp is not being displayed. Thanks for your help in advance
import React from 'react';
import { View, StyleSheet, Text, Button, TouchableHighlight, Alert, Dimensions} from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
import PopUpView from './src/PopUpView';
class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
popUpIsVisible: false,
};
}
setPopUpIsVisible(isVisible){
this.setState({popUpIsVisible: isVisible });
}
render() {
this.setPopUpIsVisible = this.setPopUpIsVisible.bind(this);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor:"blue" }}>
<Text>Home Screen</Text>
<PopUpView isVisible={this.state.popUpIsVisible}/>
<Button onPress={() => {this.setPopUpIsVisible(true)}} title="Open PopUp Screen"/>
</View>
);
}
}
const RootStack = createStackNavigator(
{
Home: HomeScreen
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
PopUpView.js
import React from 'react';
import { View, Modal,StyleSheet, Text, TouchableOpacity, Dimensions} from 'react-native';
import { TabView, TabBar,SceneMap } from 'react-native-tab-view';
import Icon from 'react-native-vector-icons/SimpleLineIcons';
const FirstRoute = () => (
<View style={{ flex: 1, backgroundColor: '#ff4081' }} />
);
const SecondRoute = () => (
<View style={{ flex: 1, backgroundColor: '#673ab7' }} />
);
const ThirdRoute = () => (
<View style={{ flex: 1, backgroundColor: '#673ab7' }} />
);
export default class PopUpView extends React.Component {
constructor(props) {
super(props);
this.state = {
modalVisible:this.props.isVisible,
index: 0,
routes: [
{ key: 'first', title: 'HIGHLIGHTS' },
{ key: 'second', title: 'AMENITIES' },
{ key: 'third', title: 'FACILITIES' },
],
};
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
renderHeader = props => <TabBar
{...props}
indicatorStyle={{backgroundColor: 'red'}}
tabStyle={styles.bubble}
labelStyle={styles.noLabel}
/>;
render() {
return (
<Modal
animationType="slide"
transparent={true}
visible={this.state.modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
}}>
<View style={styles.container}>
<View style={styles.navBar}>
<Text style={styles.navBarTitle}>Test</Text>
<TouchableOpacity
onPress={() => {
this.setModalVisible(!this.state.modalVisible);
}}>
<Icon style={styles.closeButton} name="close" size={35} color="grey" />
</TouchableOpacity>
</View>
<TabView
navigationState={this.state}
renderScene={SceneMap({
first: FirstRoute,
second: SecondRoute,
third: ThirdRoute,
})}
onIndexChange={index => this.setState({ index })}
initialLayout={{ width: Dimensions.get('window').width }}
renderTabBar={props =>
<TabBar
{...props}
style={{ backgroundColor: 'white' }}
indicatorStyle={{backgroundColor: 'black'}}
tabStyle={styles.bubble}
labelStyle={styles.label}
/>
}
/>
</View>
</Modal>
);
}
}
const styles = StyleSheet.create({
container: {
flex:1,
margin: 50,
marginLeft: 20,
marginRight: 20,
marginBottom: 20,
backgroundColor: "white",
borderWidth: 1,
borderColor: "grey",
flexDirection: 'column'
},
navBar:{
height:70,
justifyContent: 'space-between',
alignItems: 'center',
flexDirection: 'row',
borderBottomColor: 'lightgrey',
borderBottomWidth: 1,
},
navBarTitle:{
fontSize: 25,
fontFamily: 'Optima',
paddingLeft:15,
},
closeButton:{
paddingRight:12,
},
label: {
color: 'black'
}
})
The problem with your code is that you are using the state inside the PopUpView which does not change when you change the external prop. to fix this you should use the componentwillreceiveprops and update your state accordingly.
componentWillReceiveProps(nextProps){
if(this.props.isVisible!=nextProps.isVisible){
this.setState({modalVisible:nextProps.isVisible})
}
}
The better approach will be using the this.props.isVisible as the visible prop for the Model.
In this scenario you will have to pass a function as a prop to popupview which will set the popUpIsVisible to false.
Something like below
<PopUpView isVisible={this.state.popUpIsVisible}
onDismiss={()=>{this.setState({popUpIsVisible:false})}}/>
You can call the onDismiss inside the child as
<Modal visible={this.props.isVisible}>
<TouchableHighlight
onPress={() => {
this.props.onDismiss();
}}>
<Text>Hide Modal</Text>
</TouchableHighlight>
</Modal>
The second approach is better as the visibility of the child is controlled by the parent.
Add below line into constructor after state defining
this.setPopUpIsVisible = this.setPopUpIsVisible.bind(this);

Modal and FlatList

i work on my first react-native project and its also my firts javascript work. I want at least a news-app with own database informations. The backend is already finish. Now im in struggle with the app- i want an Popup with Modal with informations from my api like news_image, news_content and news_title. The News are in the FlatList and now i want to click on a item to show the content in an modal popup. so, here is my code where im struggle. i get always an error. so how can i fix this problem? tanks a lot!
import React from "react";
import {
AppRegistry,
FlatList,
Image,
Platform,
ScrollView,
StyleSheet,
Text,
TouchableOpacity,
View,
ActivityIndicator,
ListView,
YellowBox,
Alert,
TextInput
} from "react-native";
import { WebBrowser } from "expo";
import Button from "react-native-button";
import Modal from "react-native-modalbox";
import Slider from "react-native-slider";
import { MonoText } from "../components/StyledText";
export default class NewsFeed extends React.Component {
static navigationOptions = {
title: "HomeScreen"
};
constructor(props) {
super(props);
this.state = {
isLoading: true
};
YellowBox.ignoreWarnings([
"Warning: componentWillMount is deprecated",
"Warning: componentWillReceiveProps is deprecated"
]);
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: 0.5,
width: "100%",
backgroundColor: "#000"
}}
/>
);
};
webCall = () => {
return fetch("http://XXXXXXXXXXXX.com/connection.php")
.then(response => response.json())
.then(responseJson => {
this.setState(
{
isLoading: false,
dataSource: responseJson
},
function() {
// In this block you can do something with new state.
}
);
})
.catch(error => {
console.error(error);
});
};
onClose() {
console.log("Modal just closed");
}
onOpen() {
console.log("Modal just opened");
}
onClosingState(state) {
console.log("the open/close of the swipeToClose just changed");
}
componentDidMount() {
this.webCall();
}
render() {
if (this.state.isLoading) {
return (
<View
style={{ flex: 1, justifyContent: "center", alignItems: "center" }}
>
<ActivityIndicator size="large" />
</View>
);
}
return (
<View style={styles.MainContainer}>
<FlatList
data={this.state.dataSource}
ItemSeparatorComponent={this.FlatListItemSeparator}
renderItem={({ item }) => (
<View style={{ flex: 1, flexDirection: "row" }}>
<Image
source={{ uri: item.news_image }}
style={styles.imageView}
/>
<Text
onPress={() => this.refs.modal.open()}
style={styles.textView}
>
{item.news_title}
{"\n"}
<Text style={styles.textCategory}>{item.author}</Text>
</Text>
<Text style={styles.textViewDate}>{item.created_at}</Text>
<Modal
style={[styles.modal]}
position={"bottom"}
ref={"modal"}
swipeArea={20}
>
<ScrollView>
<View style={{ width: "100%", paddingLeft: 10 }}>
{item.news_content}
</View>
</ScrollView>
</Modal>
</View>
)}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
MainContainer: {
justifyContent: "center",
flex: 1,
margin: 5
},
imageView: {
width: "25%",
height: 100,
margin: 7,
borderRadius: 7
},
textView: {
width: "100%",
height: "100%",
textAlignVertical: "center",
padding: 10,
fontSize: 20,
color: "#000"
},
textViewDate: {
width: "30%",
textAlignVertical: "center",
padding: 15,
color: "#afafaf"
},
textCategory: {
color: "#d3d3d3",
fontSize: 12
},
modal: {
justifyContent: "center",
alignItems: "center",
height: "90%"
}
});
Check the code below and compare it with your code.
I am not sure where your error is located or what your exact error is, but you can check the example code below, which is similar to yours, for comparison.
I am using 'Axios' over fetch() because of the automatic transformation to JSON and some other beneficial stuff.
npm install --save axios
Code:
import React, { Component } from 'react'
import {
ActivityIndicator,
FlatList,
Image,
ScrollView,
Text,
TouchableOpacity,
View
} from 'react-native';
import Axios from 'axios';
import Modal from "react-native-modalbox";
export default class NewsFeed extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: [],
selectedIndex : -1
}
}
componentDidMount = () => {
Axios.get('<URL>')
.then(response => {
const { data } = response;
this.setState({dataSource : data});
}).catch(error => {
const { data } = error;
console.log(data);
});
}
_openModal = index => {
this.setState({ selectedIndex : index });
this.modalReference.open();
}
_renderSeparator = () => {
return <View style={{ flex: 1, borderBottomWidth: 0.5, borderBottomColor: '#000000' }} />
}
_renderItem = ({item, index}) => {
const {news_image, news_title, news_content, author, created_at} = item;
return <TouchableOpacity onPress={() => this._openModal(index)} >
<View style={{ flex: 1, flexDirection: 'row' }}>
<Image style={{ flex: 1, width: null, height: 200 }} source={{ uri: news_image }} />
<Text>{news_title}</Text>
<Text>{author}</Text>
<Text>{created_at}</Text>
</View>
</TouchableOpacity>;
}
render = () => {
const { dataSource, selectedIndex } = this.state;
const { news_content } = dataSource[selectedIndex];
return dataSource.length === 0 ?
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<ActivityIndicator size="large" />
</View> :
<View style={styles.MainContainer}>
<FlatList
data={dataSource}
keyExtractor={(item, index) => index.toString()}
ItemSeparatorComponent={this._renderSeparator}
renderItem={this._renderItem}
/>
<Modal ref={reference => modalReference = reference}>
<ScrollView style={{ flex: 1, padding: 20 }}>
<Text>{news_content}</Text>
</ScrollView>
</Modal>
</View>
}
}
I think the issue is in modal,
Can you re-write the code like below?
return (
<View style={styles.MainContainer}>
<FlatList
data={this.state.dataSource}
ItemSeparatorComponent={this.FlatListItemSeparator}
renderItem={({ item }) => (
<View style={{ flex: 1, flexDirection: "row" }}>
<Image source={{ uri: item.news_image }} style={styles.imageView} />
<Text onPress={() => { this.setState({ item: item.news_content }, () => this.refs.modal.open()); }} style={styles.textView}>
{item.news_title}
<Text style={styles.textCategory}>{item.author}</Text>
</Text>
<Text style={styles.textViewDate}>{item.created_at}</Text>
</View>
)}
keyExtractor={(item, index) => index.toString()}
/>
<Modal
style={[styles.modal]}
position={"bottom"}
ref={"modal"}
swipeArea={20}
>
<ScrollView>
<View style={{ width: "100%", paddingLeft: 10 }}>
{this.state.item}
</View>
</ScrollView>
</Modal>
</View>
);
Only single modal is enough for popup screen.
And you can try this also,
Change your reference to
ref={ref => this.modalRef = ref}
And use like this,
this.modalRef.open()

react native, moving between screens

I am using stackNavigator in react native .my problem is I want to move to another screen using stack navigator.
app.js
const CartStack=createStackNavigator({
Header:Header,
Cart:Cart
)}
Const Root=createStackNavigator({
Home:Home,
Detail:Detail,
CartStack:CartStack,
)}
Home.js
render() {
return (
<Header/>
)}
The Header Will be show on both screens (Home and Detail)
in the header i created a cart button which i want to click on
it then will be open a Cart screen. But my code is not working.
Please correct my code.
The concept in Zayco's answer is absolutely correct.
But I figured out that this.props.navigation.navigate will be undefined in navigationOptions
Here is the working example of your requirement.
class Home extends React.Component {
static navigationOptions = ({navigation}) => ({
title: 'Home',
headerRight:(<Button title="Cart" onPress={() => navigation.navigate('Cart')}/>)
})
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Scree</Text>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('Details')}
/>
</View>
);
}
}
class Details extends React.Component {
static navigationOptions = ({navigation}) => ({
title: 'Details',
headerRight:(<Button title="Cart" onPress={() => navigation.navigate('Cart')}/>)
})
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details</Text>
</View>
);
}
}
class Cart extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Cart</Text>
</View>
);
}
}
const RootStack = createStackNavigator(
{
Home: Home,
Details: Details,
Cart:Cart
},
{
initialRouteName: 'Home',
}
);
This is taken from the React Navigation documentation
You have 3 screens: Home, Details and Cart. In the header of Home and Details you have a button that will take you to the Cart screen. I suggest you take a look at the Fundementals section of the documentation.
Here is the working Snack
import React from "react";
import { View, Text, Button } from "react-native";
import { createStackNavigator, createAppContainer } from "react-navigation";
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => ({
headerTitle: "Home",
headerRight: (
<Button
onPress={() => navigation.navigate('Cart')}
title="Cart"
color="blue"
/>
)
});
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Home Screen</Text>
<Button
onPress={() => this.props.navigation.navigate('Details')}
title="Go to details"
color="red"
/>
</View>
);
}
}
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => ({
headerTitle: "Details",
headerRight: (
<Button
onPress={() => navigation.navigate('Cart')}
title="Cart"
color="blue"
/>
),
});
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Details Screen</Text>
<Button
onPress={() => this.props.navigation.navigate('Home')}
title="Go to home"
color="red"
/>
</View>
);
}
}
class CartScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Cart Screen</Text>
</View>
);
}
}
const AppNavigator = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
Cart: CartScreen
},
{
initialRouteName: "Home"
}
);
export default createAppContainer(AppNavigator);

Navigator with args

I created an Android app with Navigator.
On my first page, I want to push differents informations to the next page if I push with a button or with an other.
I created gotoNext function as below. But, I don't understand how I can replace my typedmg: 'test' by an argument which represent the button Pole or Aerial.
Thanks for your help.
class LoginPage extends React.Component {
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
navigationBar={
<Navigator.NavigationBar routeMapper= NavigationBarRouteMapper} />
} />
);
}
renderScene(route, navigator) {
return (
....
<View style={{flex: 4, flexDirection: 'column'}}>
<TouchableHighlight name='Pole' onPress={this.gotoNext}>
<Image source={require('./img/radio_damage_pole.png')} />
</TouchableHighlight>
<TouchableHighlight name='Aerial' onPress={this.gotoNext}>
<Image source={require('./img/radio_damage_aerial.png')} />
</TouchableHighlight>
</View>
...
);
}
gotoNext() {
this.props.navigator.push({
id: 'page_user_infos',
name: 'page_user_infos',
typedmg: 'test',
});
}
}
You need to set up your Navigator to pass properties by assigning the passProps spread operator to the Navigator. The best way to do that is to separate your navigator into it's own component, then assign properties to it.
I've taken your project and set up a similar functioning one here. There was another similar thread you may be able to reference here as well. Below is the code I used to get it working, I hope this helps!
https://rnplay.org/apps/UeyIBQ
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
Navigator,
Image,
TouchableHighlight, TouchableOpacity
} = React;
class Two extends React.Component {
render(){
return(
<View style={{marginTop:100}}>
<Text style={{fontSize:20}}>Hello From second component</Text>
<Text>id: {this.props.id}</Text>
<Text>name: {this.props.name}</Text>
<Text>name: {this.props.typedmg}</Text>
</View>
)
}
}
class Main extends React.Component {
gotoNext(myVar) {
this.props.navigator.push({
component: Two,
passProps: {
id: 'page_user_infos',
name: 'page_user_infos',
typedmg: myVar,
}
})
}
render() {
return(
<View style={{flex: 4, flexDirection: 'column', marginTop:40}}>
<TouchableHighlight style={{height:40, borderWidth:1, marginBottom:10}} name='Pole' onPress={ () => this.gotoNext('Pole') }>
<Text>Pole</Text>
</TouchableHighlight>
<TouchableHighlight style={{height:40, borderWidth:1, marginBottom:10}} name='Aerial' onPress={ () => this.gotoNext('Aerial') }>
<Text>Aerial</Text>
</TouchableHighlight>
</View>)
}
}
class App extends React.Component {
render() {
return (
<Navigator
initialRoute={{name: 'Main', component: Main, index: 0}}
renderScene={(route, navigator) => {
if (route.component) {
return React.createElement(route.component, { ...this.props, ...route.passProps, navigator, route } );
}
}}
navigationBar={
<Navigator.NavigationBar routeMapper={NavigationBarRouteMapper} />
} />
);
}
}
var NavigationBarRouteMapper = {
LeftButton(route, navigator, index, navState) {
if(index > 0) {
return (
<TouchableHighlight style={{marginTop: 10}} onPress={() => {
if (index > 0) {
navigator.pop();
}
}}>
<Text>Back</Text>
</TouchableHighlight>
)} else {
return null}
},
RightButton(route, navigator, index, navState) {
return null;
},
Title(route, navigator, index, navState) {
return (
<TouchableOpacity style={{flex: 1, justifyContent: 'center'}}>
<Text style={{color: 'white', margin: 10, fontSize: 16}}>
Data Entry
</Text>
</TouchableOpacity>
);
}
};
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 28,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
fontSize: 19,
marginBottom: 5,
},
});
AppRegistry.registerComponent('App', () => App);