Change screen FlatList onPress - react-native

I have two screen.
First screen is HomeScreen, second screen is ProfileScreen.
I used FlatList on HomeScreen and i wanna push to navigation to another screen. But when i used that codes, i saw that error message: "Can not read property 'navigate' of undefined"
Code like that
class ProfileScreen extends Component {
static navigationOptions = {
title: 'Profile',
};
render() {
const { navigate } = props.navigation;
return <Text>Hello, I am profile!</Text>;
}
}
class HomeScreen extends Component {
static navigationOptions = {
title: 'Home',
};
constructor(props) {
super(props);
this.state = {
data: [],
};
}
getScreen() {
this.props.navigation.navigate('Profile')
}
render() {
return (
<View>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<TouchableHighlight underlayColor= 'transparent' onPress= {this.getScreen}>
<View style= {{width: 300, height: 'auto'}} >
<Text> {item.title} </Text>
<View style= {{width: 300, height: 1, backgroundColor: 'red', marginBottom: 30, marginTop: 15}} />
</View>
</TouchableHighlight>
)}
/>
</View>
);
}
}
const AppNavigator = StackNavigator({
Home: { screen: HomeScreen },
Profile: { screen: ProfileScreen }
});

You're losing the context of this in your implementation. Fix it with function call:
renderItem={({ item }) => (
<TouchableHighlight underlayColor='transparent' onPress={() => this.getScreen()}>
...
</TouchableHighlight>
)}
In addition, you can use pattern:
const { navigate } = this.props.navigation;
navigate('Profile');

Inside the constructor bind this to your getScreen method.
Simply add following line inside constructor.
this.getScreen = this.getScreen.bind(this);

Related

How Can I add Hamburger icon menu in React-Native

I am fairly new to Navigation in react-native but i have been able to pick up few things here now i want o add the Hamburger icon to it to do a Proper Menu bar. Since i am fairly new to this, I need help in every way.
My code Looks something like this
import React , {Component} from 'react';
import { View, Text, Image , StyleSheet } from 'react-native';
import { createAppContainer } from 'react-navigation';
import { createDrawerNavigator } from 'react-navigation-drawer';
class Home extends React.Component{
static navigationOptions = {
drawerLabel: 'Home',
drawerIcon: ({ tintColor }) => (
<Image
source={{uri:'http://imageholder.freeasphost.net/home.png'}}
style={[styles.icon, { tintColor: tintColor }]}
/>
),
};
render()
{
return(
<View>
<Text> Welcome to Home screen</Text>
</View>
);
}
}
class Profile extends React.Component{
static navigationOptions = {
drawerLabel: 'Profile',
drawerIcon: ({ tintColor }) => (
<Image
source={{uri:'http://imageholder.freeasphost.net/profile.png'}}
style={[styles.icon, { tintColor: tintColor }]}
/>
),
};
render()
{
return(
<View>
<Text>Welcome to Profile screen</Text>
</View>
);
}
}
class Settings extends React.Component{
static navigationOptions = {
drawerLabel: 'Settings',
drawerIcon: ({ tintColor }) => (
<Image
source={{uri:'http://imageholder.freeasphost.net/settings.png'}}
style={[styles.icon, { tintColor: tintColor }]}
/>
),
};
render()
{
return(
<View>
<Text>Welcome to Settings Screen</Text>
</View>
);
}
}
const MyDrawerNavigator = createDrawerNavigator({
Home:{
screen:Home
},
Settings:{
screen:Settings
},
Profile:{
screen:Profile
},
});
const MyApp = createAppContainer(MyDrawerNavigator);
export default class App extends Component {
render() {
return (
<MyApp/>
);
}
}
const styles = StyleSheet.create({
icon: {
width: 24,
height: 24,
},
});
Like i wanted to use some drawer navigation uri to do it but how to start is the main worry, hence I wanted to know how and what i must do.
I'll always prefer making your own custom component rather than any library.
It's simple, first download icon like this or your icon and create a view box, and then on the image add touchable opacity so that when a user clicks, it will expand
will turn into this
Now steps are like that,
renderUnExpanded=()=>(
<View>
<TouchableOpacity onPress = {this.flipState} >
<Icon />
</TouchableOpacity>
<View>
)
renderExpanded = () =>(
<View>
<TouchableOpacity onPress = {this.flipState} >
<Icon />
</TouchableOpacity>
<ProfileIcon />
<SignoutIcon />
<View>
)
now flipState will be a function to toggle expanded state,
flipState =() => {
this.setState({optionVisible:!this.state.optionVisible})
}
and now in render function , show accordingly to state,
render(){
return(
{this.state.optionVisible?this.renderExpanded():this.renderUnExpanded()}
)
}
hope its clear, otherwise ask any doubts

having problem with react-native navigation | undefined is not an object (evaluating '_this.props.navigation')

hi i'm working on a new react-native app, but i had some issues with the navigation from a component to a screen.
this is the link for the code on snack: https://snack.expo.io/#mimonoux/my-app-navigation-test
i have already tried this
<ButtonCarte onPress={() => this.props.navigation.navigate('Carte') } />.
but it didn't work. please if anyone could help me with this please check the snack link and take a deep look at the easy code i made for my real problem
I saw your problem now. With react-navigation,
navigation props exists in a component when : either the component is configured in your route configuration object that you defined in App.js, either you use the withNavigation HOC ( https://reactnavigation.org/docs/en/with-navigation.html ).
Now in the Medicine_listDetail component this.props.navigation does not exist since Medicine_listDetail does not appear in your route and also the props object should not be read by this.props in a functional component. You can do one of this two way :
const Medicine_listDetail = ({medicine, navigation}) => {
// i'm passing navigation props comme from parent component that have
// navigation object
// ...
}
// OR you can do
const Medicine_listDetail = (props) => {
const { medicine, navigation } = props;
// i'm passing navigation props comme from parent component that have
// navigation object
// ...
}
Hence the following is an attempt at a solution that work for me.
Medicine_listDetail component : i'm passing navigation props come from
parent component that have navigation object
...
const Medicine_listDetail = ({medicine, navigation}) => {
const {title, coordinate} = medicine;
const {
headerContentStyle,
headerTextStyle,
cityTextStyle,
addTextStyle,
infoContainerStyle,
buttonsContainerStyle,
specialityTextStyle,
buttonStyle,
textStyle
} = styles
return (
<View>
<View style={headerContentStyle}>
<Text style={headerTextStyle}>{title}</Text>
</View>
<View style={buttonsContainerStyle}>
<ButtonCarte onPress={() => navigation.navigate('Carte') }>
</ButtonCarte>
</View>
</View>
);
};
...
ButtonCarte component
const ButtonCarte = ({onPress, children}) => {
const {buttonStyle, textStyle} = styles;
return (
<TouchableOpacity onPress={() => onPress()} style={buttonStyle}>
<Ionicons name={'ios-pin'} size={20} color="white" />
<Text style={textStyle}>
Voir La Carte
</Text>
</TouchableOpacity>
);
};
Medicin component : in all_medicine() function, i'm passing navigation object in props of Medicine_listDetail component. So this is the trick.
export default class Medicin extends React.Component {
constructor(props) {
super(props);
this.state = {
list_allMedicine: data_allMedicine,
selectedIndex: 0,
};
this.updateIndex = this.updateIndex.bind(this);
}
updateIndex(selectedIndex) {
this.setState({ selectedIndex });
}
all_medicine() {
const { navigation } = this.props;
return this.state.list_allMedicine.map(medicine => (
<Medicine_listDetail key={medicine.title} medicine={medicine} navigation={navigation} />
));
}
render() {
const buttons = ['Tout', '...', '...', '...'];
const { selectedIndex } = this.state;
return (
<View style={{ flex: 1}}>
<View
style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ButtonGroup
onPress={this.updateIndex}
selectedIndex={selectedIndex}
buttons={buttons}
containerStyle={{ borderRadius:8 }}
/>
</View>
<Divider
style={{
backgroundColor: 'lightgrey',
marginHorizontal: 5,
height: 2,
}}
/>
<View style={{ flex: 5 }}>
{this.state.selectedIndex == 0 ? (
<ScrollView>{this.all_medicine()}</ScrollView>
) : (
<Text>test</Text>
)}
</View>
</View>
);
}
}
At least in App.js, i change the name of carte tab from Cart to Carte because of your RootStack stack.
export default createAppContainer(
createBottomTabNavigator(
{
Home: {
screen: Home,
navigationOptions: {
tabBarLabel: 'Home',
tabBarIcon: ({ tintColor }) => (
<Ionicons name={'ios-home'} size={25} color={tintColor} />
),
},
},
Medicin: {
screen: Medicin,
navigationOptions: {
tabBarLabel: 'Medicin',
tabBarIcon: ({ tintColor }) => (
<Image
source={require('./assets/images/Dashboard/drawable-xhdpi/doctor_heart.png')}
style={{ width: 25, height: 20, tintColor: tintColor }}
/>
),
},
},
Carte: {
screen: Carte,
navigationOptions: {
tabBarLabel: 'Carte',
tabBarIcon: ({ tintColor }) => (
<Ionicons name={'ios-map'} size={25} color={tintColor} />
),
},
},
},
{
tabBarOptions: {
activeTintColor: 'black',
inactiveTintColor: 'gray',
},
}
)
);
I test this and it work for me.
try adding this:
import { NavigationEvents, NavigationActions } from 'react-navigation';
Here is a screenshot of what's available in props in reference to the comments below:
Here is a screenshot of what I mentioned in the comments. You can see where I added a console.log. It shows in the console that although navigation is in this.props, actions within navigation is empty. I think that is the source of the problem. If you put more console.logs like the one I've done you will see where in the project it loses that information.

How to navigate between screens from any js class that is not inside App.js in React Native

It's very easy to navigate from one screen to another that is inside App.js class. What I have done is made three classes : App.js, SearchList.js and Detail.js. But i am facing issue that how to navigate from searchList.js to Detail.js on click any view inside searchList.js class. Should i use StackNavigator again in searchList.js or declare all classes in App.js ?
App.js
import React from 'react';
import { Image,Button, View, Text ,StatusBar,StyleSheet,Platform,TouchableOpacity,ImageBackground,Picker,Alert,TouchableHighlight} from 'react-native';
import { StackNavigator,DrawerNavigator,DrawerItems } from 'react-navigation';
import {Constants} from "expo";
import SearchList from './classes/SearchList';
import Detail from './classes/Detail';
const DrawerContent = (props) => (
<View>
<View
style={{
backgroundColor: '#f50057',
height: 160,
alignItems: 'center',
justifyContent: 'center',
}}
>
<Text style={{ color: 'white', fontSize: 30 }}>
Header
</Text>
</View>
<DrawerItems {...props} />
</View>
)
class HomeScreen extends React.Component {
static navigationOptions = {
drawerLabel: 'Home',
drawerIcon: ({ tintColor }) => (
<Image
source={require('./images/crown.png')}
style={[styles.icon, {tintColor: '#f50057'}]}
/>
),
};
constructor(){
super();
this.state={PickerValueHolder : ''}
}
GetSelectedPickerItem=()=>{
Alert.alert(this.state.PickerValueHolder);
}
render() {
return (
<ImageBackground source={require('./images/green.png')} style={styles.backgroundImage} >
<TouchableOpacity onPress={() =>this.props.navigation.navigate('DrawerOpen')}>
<Image
source={require('./images/menu-button.png')}
style={styles.imagesStyle}
/>
</TouchableOpacity>
<View style={styles.columnContainer}>
<TouchableHighlight style={styles.search} underlayColor='#fff' onPress={() => this.props.navigation.navigate('SearchList')}>
<Text style={styles.searchText}>Search Hotels</Text>
</TouchableHighlight>
</View>
</ImageBackground >
);
}
}
class DetailsScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go to Details... again"
onPress={() => this.props.navigation.navigate('Details')}
/>
</View>
);
}
}
const styles = StyleSheet.create({
backgroundImage: {
flex: 1,
width: null,
height: null,
marginTop: Constants.statusBarHeight,
},
search:{
marginTop:20,
paddingTop:15,
borderRadius:8,
borderColor: '#fff'
},
searchText:{
color:'#fff',
textAlign:'center',
}
// backgroundColor: '#ef473a', // app color
});
const HomeStack = StackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: ({ navigation }) => ({
header: null,
})
},
SearchList: { screen: SearchList },
Detail: { screen: Detail},
});
const RootStack = DrawerNavigator(
{
Home: {
screen: HomeStack,
},
DetailsScreen: {
screen: DetailsScreen,
},
},
{
initialRouteName: 'Home',
}
);
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
SearchList.js
import React, { Component } from 'react';
import { StyleSheet, Platform, View, ActivityIndicator, FlatList, Text, Image, Alert, YellowBox,ImageBackground } from 'react-native';
import { StackNavigator,} from 'react-navigation';
import Detail from './classes/Detail';
export default class SearchList extends Component {
constructor(props) {
super(props);
this.state = {isLoading: true}
YellowBox.ignoreWarnings([
'Warning: componentWillMount is deprecated',
'Warning: componentWillReceiveProps is deprecated',
]);
}
GetItem (flower_name) {
Alert.alert(flower_name);
}
FlatListItemSeparator = () => {
return (
<View
style={{
height: .0,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}
webCall=()=>{
return fetch('https://reactnativecode.000webhostapp.com/FlowersList.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);
});
}
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}) =>
<ImageBackground source= {{ uri: item.flower_image_url }} style={styles.imageView}
onPress={() => this.props.navigation.navigate('Detail')}>
</ImageBackground>
}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
MainContainer :{
justifyContent: 'center',
flex:1,
margin: 5,
marginTop: Constants.statusBarHeight , //(Platform.OS === 'ios') ? 20 : 14,
},
imageView: {
width: '100%',
height: 220 ,
margin: 7,
borderRadius : 40,
},
});
const HomeStack = StackNavigator({
Detail: { screen: Detail},
});
export default class App extends React.Component {
render() {
return <HomeStack />;
}
}
Any help would be appreciable.
To navigate to any screen you need to have a navigation object. Navigation object can be provided in two ways
By declaring it in StackNavigator
By explicitly passing it as a prop to some other screen
If you use the first approach, and you need to navigate from SecondScreen to ThirdScreen, both of your screens should be declared in the StackNavigator first, only then navigation will be successful.
If you are using any trivial component ( such as a modal box ) to navigate to another screen, all you need to do is pass the navigation props (this.props.navigation) to the modal box component and use the props to navigate to another screen. The only requirement here being, this.props.navigation should be available in the class where the modal box component is loaded.
EDIT
As requested, here is the snippet
const App = StackNavigator({
FirstScreen: { screen: FirstScreen},
SecondScreen: { screen: SecondScreen},
ThirdScreen: { screen: ThirdScreen}
})
export default App;
In your SecondScreen, declare an object const { navigate } = this.props.navigation; and on a button click, use this object to navigate to another screen navigate("ThirdScreen");
Regarding the second approach, if your component is a modal, you can pass the navigate object as - <Modal navigation={navigate} /> and in the modal component you can use it as this.props.navigation("ThirdScreen");
Hope it clarifies now.
Support we have js named SecondScreen.js at the same directory level as App.js then we should import it like this in App.js
import SecondScreen from './SecondScreen';
It worked for me. Hope this helps to you too.
I think you are trying to implement the functionality of a stack navigator.
Go to React-Navigation-Docs. In stack navigator you can make stack of screens, and navigate from one to another. Inside index.js :
import { StackNavigator, TabNavigator } from "react-navigation";
import SplashScreen from "./src/screens/start/splash";
import LoginScreen from "./src/screens/start/login";
import DomainScreen from "./src/screens/start/domain";
const App = StackNavigator(
{
Splash: {
screen: SplashScreen,
},
Domain: {
screen: DomainScreen,
},
Login: {
screen: LoginScreen,
},
Tabs: {
screen: HomeTabs,
}
},
{
initialRouteName: "Splash",
}
);
AppRegistry.registerComponent("app_name", () => App);
then you can navigate to any of these screens using this.props.navigation.navigate("ScreenName")

Open Drawer by clicking in header of containing StackNavigator

This is the component which contains my Drawer
export default class StackInView extends React.Component {
render() {
const Stack = StackNavigator({
DrawerStack: { screen: DrawerInView }
}, {
headerMode: 'float',
});
return (
<View style={{ flex: 1 }}>
<Stack />
</View>
);
}
}
The following is where I define my button. I want to define the button in navigationOptions of the screen, because the button should only appear on the screen with the drawer. But clicking the button doesn't work can you help me pls?
... imports ...
export default class DrawerInView extends React.Component {
static navigationOptions = {
title: "Yeah?",
headerRight: <Button title="Menu" onPress={() => {NavigationActions.navigate("DrawerOpen")}}/>
}
constructor(props) {
super(props);
}
render() {
const Drawer = DrawerNavigator({
"one": {
screen: () => {
return (<TabsInView select="something" />)
},
},
"two": {
screen: () => {
return (<TabsInView select="something else" />)
},
}
})
return (
<View style={{ flex: 1 }}>
<Drawer />
</View>
);
}
}
You can open DrawerNavigation on button click like this.
<Button title="Menu" onPress ={ ( ) => this.props.navigation.openDrawer()} />
Don't put Stack into View. It's hard to understand and you break all props.
And the reason it doesn't work is that navigationOptions in second code is not for the drawer but for the StackNavigator in the first code. So it can't execute drawer's navigation.navigate("DrawerOpen") because it's StackNavigator's.
And I highly recommend you to change your app's hierarchy. It's really hard that child Drawer passes its navigation to parent Stack's right button.
Then, it would look like this.
const MyStack = StackNavigator({
Tabs:{ screen: MyTabs, navigationOptions:(props) => ({
headerRight:
<TouchableOpacity onPress={() => {props.screenProps.myDrawerNavigation.navigate('DrawerOpen')}}>
<Text>Open Drawer</Text>
</TouchableOpacity>
})}
}
, {navigationOptions:commonNavigationOptions})
const MyDrawer = DrawerNavigator({
stack1: {
screen: ({navigation}) => <MyStack screenProps={{myDrawerNavigation:navigation}} />,
},
stack2: {
//more screen
}
})

Sending props with Tabs from 'react-native-tabs'

I am using Tabs from 'react-native-tabs' to navigate from one screen to another, how can I send props to the individual components of the tabs?
I am using the following code to display tabs,
import Tabs from 'react-native-tabs';
<Tabs
selected={page}
style={styles.tabbar}
selectedStyle={{color:'black'}}
onSelect={el=>this.setState({page:el.props.name})}
>
<Text style={styles.tabbarText} name={Contact}>Contact</Text>
<Text style={styles.tabbarText} name={Messages}>Messages</Text>
<Text style={styles.tabbarText} name={Profile}>Profile</Text>
</Tabs>
I figured it out, you can mention the props in the
<this.state.page style={styles.pageContainer} navigator={this.props.navigator}/>
line of code.
The entire render() function is here,
render() {
const { page } = this.state;
return (
<View style={styles.container}>
<this.state.page style={styles.pageContainer} navigator={this.props.navigator}/>
<Tabs
selected={page}
style={styles.tabbar}
selectedStyle={{color:'black'}}
onSelect={el=>this.setState({page:el.props.name})}
>
<Text style={styles.tabbarText} name={Contact}>Contact</Text>
<Text style={styles.tabbarText} name={Messages}>Messages</Text>
<Text style={styles.tabbarText} name={Profile}>Profile</Text>
</Tabs>
</View>
);
}
It may help you.
class Home2Screen extends React.Component {
render() {
console.log(this.props.navigation.state);
return (
<View>
</View>
);
}
}
class SettingsScreen extends React.Component {
render() {
console.log(this.props.navigation.state);
return (
<View>
</View>
);
}
}
const tab = TabNavigator(
{
Home2: { screen: Home2Screen },
Settings: { screen: SettingsScreen },
},
{}
);
class HomeScreen extends React.Component {
goToTab() {
this.props.navigation.navigate('Tab', {
carData: {some: 'data'},
});
}
render() {
return (
<View>
<Button onPress={() => { this.goToTab() }} />
</View>
);
}
}
const HomeNavigator = StackNavigator({
Home: {
screen: HomeScreen,
},
Tab: {
screen: tab,
},
}, {
mode: Platform.OS === 'ios' ? 'modal' : 'card',
});
const HomeNavigationDrawer = DrawerNavigator({
HomePage: {
screen: HomeNavigator,
},
}, {});
export default HomeNavigationDrawer;