undefined is not an object (evaluating '_this3.props.navigation.navigate') - javascript

Problem with stack navigation between the screens.
I am displaying data on my 'SveKategorije' screen.
It's basically categories buttons, when i click on button i just want to show another screen for now, but it is not working for some reason.
When i put onPress={() => this.props.navigation.navigate('screenname')}
it gives me this
error
I am using (react-native - 0.57.7)
Here is router.js code (where i declare my routes)
import React from 'react';
import { View, Text, Button } from "react-native";
import { createBottomTabNavigator, createStackNavigator } from "react-navigation";
import { Icon } from 'react-native-elements';
//TABS
import Categories from '../tabs/categories';
import Home from '../tabs/home';
import Me from '../tabs/me';
//screens for CATEGORIES
import ViceviPoKategoriji from '../components/Ispis/ViceviPoKategoriji';
//CATEGORIES STACK
export const categoriesFeedStack = createStackNavigator({
SveKategorije: {
screen: Categories,
navigationOptions: {
title: 'KATEGORIJE',
},
},
ViceviPoKategoriji: {
screen: ViceviPoKategoriji,
}
});
//TABS
export const Tabs = createBottomTabNavigator({
Categories: {
screen: categoriesFeedStack,
navigationOptions: {
title: 'Kategorije',
label: 'Kategorije',
tabBarIcon: ({ tintColor }) => <Icon name="list" size={35} color={tintColor} />,
}
},
Home: {
screen: Home,
navigationOptions: {
title: 'Pocetna',
label: 'Kategorije',
tabBarIcon: ({ tintColor }) => <Icon name="home" size={35} color={tintColor} />,
}
},
Me: {
screen: Me,
navigationOptions: {
title: 'Profil',
label: 'Kategorije',
tabBarIcon: ({ tintColor }) => <Icon name="account-circle" size={35} color={tintColor} />,
}
},
},
{
initialRouteName: "Home",
showIcon: true
},
);
Here is 'SveKategorije' screen
import React from 'react';
import { StyleSheet, Text, View, ActivityIndicator, ScrollView, Button } from 'react-native';
import { createStackNavigator, createAppContainer, StackNavigator, navigate } from 'react-navigation';
export default class SveKategorije extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: null
}
}
componentDidMount() {
return fetch('http://centarsmijeha.com/api/allCategories')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.data,
})
})
.catch((error) => {
console.log(error)
});
}
render() {
if (this.state.isLoading) {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
)
} else {
let data = this.state.dataSource.map((val, key) => {
return (
<View key={key} style={styles.item}>
<Button
onPress={() => this.props.navigation.navigate('ViceviPoKategoriji')}
title={val.categoryName}
/>
</View>
);
});
return (
<ScrollView>
{data}
</ScrollView >
);
}
}
}
//CSS
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
width: '100%'
},
item: {
flex: 1,
alignSelf: 'stretch',
width: '100%',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center'
}
});
and here is 'ViceviPoKategoriji' screen ( the screen that should be displayed on click of any buttons from 'SveKategorije' screen )
import React from 'react';
import { StyleSheet, Text, View, ActivityIndicator, ScrollView } from 'react-native';
export default class ViceviPoKategoriji extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: null,
}
}
componentDidMount() {
return fetch('http://centarsmijeha.com/api/jokesByCategory/16')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.data,
})
})
.catch((error) => {
console.log(error)
});
}
render() {
if (this.state.isLoading) {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
)
} else {
let data = this.state.dataSource.map((val, key) => {
return <View key={key} style={styles.item}><Text>{val.jokeText}</Text></View>
});
return (
<ScrollView>
{data}
</ScrollView >
);
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
item: {
flex: 1,
alignSelf: 'stretch',
marginTop: 50,
marginRight: '15%',
marginLeft: '15%',
width: '70%',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
borderBottomWidth: 1,
borderBottomColor: '#eee'
}
});

React-navigation is props based navigation.
I think your component don't have navigation props.
Please check whether your component have navigation props.
do
render() {
console.log(this.props.navigation)
// or debugger
return (
If result of console.log is undefined, then add 'import SveKategorije' to your routing file.

You have to do few more setups for navigating from the component.You can get access to a navigator through a ref and pass it to the NavigationService which we will later use to navigate.
https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html

In my case I accidentally used this.props.navigation inside functional component. If any one made a mistake like this, will check u r code once again.

Related

View config getter callback for component 'H' must be a function (received undefined)

Error is:
Invariant Violation: View config getter callback for component 'H' must be a function (received undefined)
I'm using react-native to make application and error happens when I clicked login button in MainLogin.js file. (It has to move to mainpage when clicking login button in login page)
I searched a lot but cannot know what is component 'H'.
attatched index.js (src/screens/index.js) and MainLogin.js (src/screens/MainLogin.js)
<index.js>
import React from 'react';
import {
Text
} from 'react-native';
import { createAppContainer } from "react-navigation";
import { createStackNavigator } from "react-navigation-stack";
import { createBottomTabNavigator } from "react-navigation-tabs";
import LoginScreen from './MainLogin';
import HomeScreen from './MainPage';
import DiaryScreen from './Diarymemo';
import StatScreen from './MoodStatistics';
import CommuScreen from './Community';
import StoreScreen from './Store';
const HomeStack = createStackNavigator(
{
HomeScreen
},
{ defaultNavigationOptions : ({navigation}) => ({
title: 'Home'}),
}
);
const DiaryStack = createStackNavigator(
{
DiaryScreen
},
{ defaultNavigationOptions : ({navigation}) => ({
title: 'Diary'}),
}
);
const StatStack = createStackNavigator(
{
StatScreen
},
{ defaultNavigationOptions : ({navigation}) => ({
title: 'Stat'}),
}
);
const CommunityStack = createStackNavigator(
{
CommuScreen
},
{ defaultNavigationOptions : ({navigation}) => ({
title: 'Network'}),
}
);
const StoreStack = createStackNavigator(
{
StoreScreen
},
{ defaultNavigationOptions : ({navigation}) => ({
title: 'Store'}),
}
);
const TabNavigator = createBottomTabNavigator(
InitialRouteName = 'Home',
{
Diary: DiaryStack,
Stat: StatStack,
Home: HomeStack,
Network: CommunityStack,
Store: StoreStack,
},
{
defaultNavigationOptions: ({navigation}) => ({
tabBarIcon: ({focused, horizontal, tintColor}) => {
const {routeName} = navigation.state;
let icon = "▲";
if(routeName === 'Diary'){
icon = "📓";
} else if(routeName === 'Stat'){
icon = "📊"
} else if(routeName === 'Home'){
icon = "🍎"
} else if(routeName === 'Network'){
icon = "👫"
} else if(routeName === 'Store'){
icon = "🛍"
}
// can use react-native-vector-icons
// <Icon name={iconName} size={iconSize} color={iconColor} />
return <Text style={{color: focused && "#46c3ad" || "#888"}}>{icon}</Text>
}
}),
lazy: false,
tabBarOptions: {
activeTintColor: "#46c3ad",
inactiveTintColor: "#888",
},
}
);
const AppStack = createStackNavigator(
{
LoginScreen: LoginScreen,
TabNavigator: {
screen: TabNavigator,
navigationOptions: ({navigation}) => ({
headerShown: false,
}),
},
}
);
export default createAppContainer(AppStack);
<MainLogin.js>
import React, {Component} from 'react';
import {
View,
Text,
TextInput,
TouchableOpacity,
StyleSheet
} from 'react-native';
import {widthPercentageToDP as wp, heightPercentageToDP as hp} from 'react-native-responsive-screen';
export default class LoginScreen extends Component{
static navigationOptions = {
headerShown: false,
};
_doLogin(){
// do something
this.props.navigation.replace('TabNavigator')
}
render(){
return (
<View style={styles.container}>
<View style={styles.titleArea}>
<Text style={styles.title}>MoodiBuddy</Text>
</View>
<View style={styles.formArea}>
<TextInput
style={styles.textForm}
placeholder={"ID"}/>
<TextInput
style={styles.textForm}
placeholder={"Password"}/>
</View>
<View style={styles.buttonArea}>
<TouchableOpacity
style={styles.button}
onPress={this._doLogin.bind(this)}>
<Text style={styles.buttonTitle}>Login</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
paddingLeft: wp('10%'),
paddingRight: wp('10%'),
justifyContent: 'center',
},
titleArea: {
width: '100%',
padding: wp('10%'),
alignItems: 'center',
},
title: {
fontSize: wp('10%'),
},
formArea: {
width: '100%',
paddingBottom: wp('10%'),
},
textForm: {
borderWidth: 0.5,
borderColor: '#888',
width: '100%',
height: hp('5%'),
paddingLeft: 5,
paddingRight: 5,
marginBottom: 5,
},
buttonArea: {
width: '100%',
height: hp('5%'),
},
button: {
backgroundColor: "#46c3ad",
width: "100%",
height: "100%",
justifyContent: 'center',
alignItems: 'center',
},
buttonTitle: {
color: 'white',
},
})

How to solve the problem for stackNavigator

Here In this code I am populating json data on ListView ..and after click item value, passing that particular value on new screen.. .
I have created MainActivity where I am populating JSON value and on SecondActivity sendng selected item value ,
To navigate between class I am using
export default MyNewProject = StackNavigator(
{
First: { screen: MainActivity },
Second: { screen: SecondActivity }
});
// getting error "undefined is not a function (evaluating '(0 _reactnavigation.stacknavigator)')"..
import React, { Component } from 'react';
import { StyleSheet, Text, View, ListView, ActivityIndicator } from 'react-native';
import { StackNavigator } from 'react-navigation';
class MainActivity extends Component {
constructor(props) {
super(props);
this.state = {
// Default Value of this State.
Loading_Activity_Indicator: true
}
}
componentDidMount() {
return fetch('https://reactnativecode.000webhostapp.com/FruitsList.php')
.then((response) => response.json())
.then((responseJson) => {
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.setState({
Loading_Activity_Indicator: false,
dataSource: ds.cloneWithRows(responseJson),
}, function() {
// In this block you can do something with new state.
});
})
.catch((errorMsg) => {
console.error(errorMsg);
});
}
ListViewItemSeparator = () => {
return (
<View
style={{
height: .5,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}
Navigate_To_Second_Activity=(fruit_name)=>
{
//Sending the JSON ListView Selected Item Value On Next Activity.
this.props.navigation.navigate('Second', { JSON_ListView_Clicked_Item: fruit_name });
}
static navigationOptions =
{
title: 'MainActivity',
};
render()
{
if (this.state.Loading_Activity_Indicator) {
return (
<View style={styles.ActivityIndicator_Style}>
<ActivityIndicator size = "large" color="#009688"/>
</View>
);
}
return (
<View style={styles.MainContainer}>
<ListView
dataSource={this.state.dataSource}
renderSeparator= {this.ListViewItemSeparator}
renderRow={(rowData) => <Text style={styles.rowViewContainer}
onPress={this.Navigate_To_Second_Activity.bind(this, rowData.fruit_name)} >{rowData.fruit_name}</Text>}
/>
</View>
);
}
}
class SecondActivity extends Component
{
static navigationOptions =
{
title: 'SecondActivity',
};
render()
{
return(
<View style = { styles.MainContainer }>
<Text style = { styles.TextStyle }> { this.props.navigation.state.params.JSON_ListView_Clicked_Item } </Text>
</View>
);
}
}
export default MyNewProject = StackNavigator(
{
First: { screen: MainActivity },
Second: { screen: SecondActivity }
});
const styles = StyleSheet.create(
{
MainContainer:
{
justifyContent: 'center',
flex:1,
margin: 10
},
TextStyle:
{
fontSize: 23,
textAlign: 'center',
color: '#000',
},
rowViewContainer:
{
fontSize: 17,
paddingRight: 10,
paddingTop: 10,
paddingBottom: 10,
},
ActivityIndicator_Style:
{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
left: 0,
right: 0,
top: 0,
bottom: 0,
}
});
// I have tried may thing but not getting the solutions .. I am stuck , this might be small thing but not getting the solutions..
I need help for this ..
Thanks
Try this code
import React, { Component } from 'react';
import { StyleSheet, Text, View, ListView, ActivityIndicator } from 'react-native';
import { createStackNavigator } from 'react-navigation'
class MainActivity extends Component {
constructor(props) {
super(props);
this.state = {
// Default Value of this State.
Loading_Activity_Indicator: true
}
}
componentDidMount() {
return fetch('https://reactnativecode.000webhostapp.com/FruitsList.php')
.then((response) => response.json())
.then((responseJson) => {
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.setState({
Loading_Activity_Indicator: false,
dataSource: ds.cloneWithRows(responseJson),
}, function() {
// In this block you can do something with new state.
});
})
.catch((errorMsg) => {
console.error(errorMsg);
});
}
ListViewItemSeparator = () => {
return (
<View
style={{
height: .5,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}
Navigate_To_Second_Activity=(fruit_name)=>
{
//Sending the JSON ListView Selected Item Value On Next Activity.
this.props.navigation.navigate('Second', { JSON_ListView_Clicked_Item: fruit_name });
}
static navigationOptions =
{
title: 'MainActivity',
};
render()
{
if (this.state.Loading_Activity_Indicator) {
return (
<View style={styles.ActivityIndicator_Style}>
<ActivityIndicator size = "large" color="#009688"/>
</View>
);
}
return (
<View style={styles.MainContainer}>
<ListView
dataSource={this.state.dataSource}
renderSeparator= {this.ListViewItemSeparator}
renderRow={(rowData) => <Text style={styles.rowViewContainer}
onPress={this.Navigate_To_Second_Activity.bind(this, rowData.fruit_name)} >{rowData.fruit_name}</Text>}
/>
</View>
);
}
}
class SecondActivity extends Component
{
static navigationOptions =
{
title: 'SecondActivity',
};
render()
{
return(
<View style = { styles.MainContainer }>
<Text style = { styles.TextStyle }> { this.props.navigation.state.params.JSON_ListView_Clicked_Item } </Text>
</View>
);
}
}
export default MyNewProject = createStackNavigator (
{
First: { screen: MainActivity },
Second: { screen: SecondActivity }
});
const styles = StyleSheet.create(
{
MainContainer:
{
justifyContent: 'center',
flex:1,
margin: 10
},
TextStyle:
{
fontSize: 23,
textAlign: 'center',
color: '#000',
},
rowViewContainer:
{
fontSize: 17,
paddingRight: 10,
paddingTop: 10,
paddingBottom: 10,
},
ActivityIndicator_Style:
{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
left: 0,
right: 0,
top: 0,
bottom: 0,
}
});
Change your code to this.
import { createStackNavigator } from 'react-navigation';
export default MyNewProject = createStackNavigator(
{
First: { screen: MainActivity },
Second: { screen: SecondActivity }
});
stackNavigator is deprecated, you should use createStackNavigator instead
More info at: https://reactnavigation.org/docs/en/stack-navigator.html
EDIT:
import { createStackNavigator } from 'react-navigation'
export default MyNewProject = createStackNavigator (
{
First: { screen: MainActivity },
Second: { screen: SecondActivity }
});

Undefined is not an object (evaluating 'this.props.navigation.navigate') _onViewApp ln 17

I did find this question in a few other places, but I'm still unable to resolve the issue with any of the help given. I got most of the code so far from this article -
https://medium.com/#austinhale/building-a-mobile-app-in-10-days-with-react-native-c2a7a524c6b4
Some of the APIs were outdated, but most of them I was able to replace with the new version - One of the APIs i changed that might be notable in regards to this question is stackNavigator -> createStackNavigator
My code is as follows:
Apps.js
import React, { Component } from 'react';
import {
FlatList,
StatusBar,
StyleSheet,
Text,
View
} from 'react-native';
import AppItem from './AppItem';
export default class Apps extends Component {
constructor(props) {
super(props);
this.state = {
apps: [
{
id: 1,
title: 'Good Business',
description: 'Make millions investing in mindtree minds',
thumbnail: 'https://img12.androidappsapk.co/300/f/5/1/com.nse.bse.sharemarketapp.png'
},
{
id: 2,
title: 'Troll WhatsApp SOS ONLY',
description: 'Have a laugh by reading all the comments in the group chat made by your coworkers',
thumbnail: 'http://icons.iconarchive.com/icons/dtafalonso/android-l/256/WhatsApp-icon.png'
}
]
}
}
_renderItem = ({ item }) => (
<AppItem
id={item.id}
title={item.title}
description={item.description}
thumbnail={item.thumbnail}
/>
);
_keyExtractor = (item, index) => item.id.toString();
render() {
return (
<View style={styles.container}>
<StatusBar
barStyle="light-content"
/>
<FlatList
data={this.state.apps}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
}
});
router.js
import React, { Component } from 'react';
import { Dimensions, Platform } from 'react-native';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
import { Icon } from 'react-native-elements';
import Apps from './screens/Apps';
import Gallery from './screens/Gallery';
import Garage from './screens/Garage';
import News from './screens/News';
import Support from './screens/Support';
import ViewApp from './screens/ViewApp';
let screen = Dimensions.get('window');
export const Tabs = createBottomTabNavigator({
'Apps': {
screen: Apps,
navigationOptions: {
tabBarLabel: 'Apps',
tabBarIcon: ({ tintColor }) => <Icon raised name="ios-apps-outline" type="ionicon" size={28} color={tintColor} />
},
},
'News': {
screen: News,
navigationOptions: {
tabBarLabel: 'News',
tabBarIcon: ({ tintColor }) => <Icon raised name="newspaper-o" type="font-awesome" size={28} color={tintColor} />
},
},
'Garage': {
screen: Garage,
navigationOptions: {
tabBarLabel: 'Garage',
tabBarIcon: ({ tintColor }) => <Icon raised name="garage" type="material-community" size={28} color={tintColor} />
},
},
'Gallery': {
screen: Gallery,
navigationOptions: {
tabBarLabel: 'Gallery',
tabBarIcon: ({ tintColor }) => <Icon raised name="picture" type="simple-line-icon" size={28} color={tintColor} />
},
},
'Support': {
screen: Support,
navigationOptions: {
tabBarLabel: 'Support',
tabBarIcon: ({ tintColor }) => <Icon raised name="ios-person-outline" type="ionicon" size={28} color={tintColor} />
},
},
});
export const AppsStack = createStackNavigator({
Apps: {
screen: Apps,
navigationOptions: ({ navigation }) => ({
header: null,
}),
},
ViewApp: {
screen: ViewApp,
navigationOptions: ({ navigation }) => ({
header: null,
tabBarVisible: false,
gesturesEnabled: false
}),
},
});
export const createRootNavigator = () => {
return createStackNavigator(
{
AppsStack: {
screen: AppsStack,
navigationOptions: {
gesturesEnabled: false
}
},
Tabs: {
screen: Tabs,
navigationOptions: {
gesturesEnabled: false
}
}
},
{
headerMode: "none",
mode: "modal"
}
);
};
AppItem.js
import React, { Component } from 'react';
import {
StyleSheet,
TouchableOpacity,
Text,
Image,
View
} from 'react-native';
import { Icon } from 'react-native-elements';
import { ViewApp } from './ViewApp';
export default class AppItem extends Component {
_onViewApp = () => {
let id = this.props.id;
this.props.navigation.navigate('ViewApp', { id: id })
}
render() {
return (
<TouchableOpacity onPress={this._onViewApp}>
<View style={styles.rowContainer}>
<Image source={{ uri: this.props.thumbnail }}
style={styles.thumbnail}
resizeMode="contain" />
<View style={styles.rowText}>
<Text style={styles.title} numberOfLines={2} ellipsizeMode={'tail'}>
{this.props.title}
</Text>
<Text style={styles.description} numberOfLines={2} ellipsizeMode={'tail'}>
{this.props.description}
</Text>
</View>
</View>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
rowContainer: {
flexDirection: 'row',
backgroundColor: '#FFF',
height: 100,
padding: 10,
marginRight: 10,
marginLeft: 10,
marginTop: 15,
borderRadius: 4,
shadowOffset: { width: 1, height: 1, },
shadowColor: '#CCC',
shadowOpacity: 1.0,
shadowRadius: 1
},
title: {
paddingLeft: 10,
paddingTop: 5,
fontSize: 16,
fontWeight: 'bold',
color: '#777'
},
description: {
paddingLeft: 10,
marginTop: 5,
fontSize: 14,
color: '#777'
},
thumbnail: {
flex: 1,
height: undefined,
width: undefined
},
rowText: {
flex: 4,
flexDirection: 'column'
}
});
You can change your onPress functionality in AppItem.js like below. Use arrow function inside your onPress onPress={() => this._onViewApp()}. Because Arrow function does not create the context "this". It refers to the context of the component that it was wrapped in. For lexical this refer this Arrow function vs function declaration / expressions: Are they equivalent / exchangeable?
import { Icon } from 'react-native-elements';
import { ViewApp } from './ViewApp';
export default class AppItem extends Component {
_onViewApp(){
let id = this.props.id;
this.props.navigation.navigate('ViewApp', { id: id })
}
render() {
return (
<TouchableOpacity onPress={() => this._onViewApp()}>
<View style={styles.rowContainer}>
<Image source={{ uri: this.props.thumbnail }}
style={styles.thumbnail}
resizeMode="contain" />
<View style={styles.rowText}>
<Text style={styles.title} numberOfLines={2} ellipsizeMode={'tail'}>
{this.props.title}
</Text>
<Text style={styles.description} numberOfLines={2} ellipsizeMode={'tail'}>
{this.props.description}
</Text>
</View>
</View>
</TouchableOpacity>
);
}
}
I wanted to follow up for everyone who's having the same issue. I just included withNavigation from 'react-native-navigation'; and exported at the end of the component like so export default withNavigation(AppItem);.

DrawerNavigation - Can't change header colour

I'm working on a react native application, and using a DrawerNavigator. Unfortunately I'm not able to change the colour of the header, my SideMenu component looks like this:
import React from 'react';
import {
TouchableHighlight,
View,
ScrollView,
Image,
Platform,
StyleSheet
} from 'react-native';
import {NavigationActions} from 'react-navigation';
import {
RkStyleSheet,
RkText,
RkTheme
} from 'react-native-ui-kitten';
import { MainRoutes } from '../routes/routes';
import { MaterialCommunityIcons } from 'react-native-vector-icons';
import { connect } from 'react-redux';
const mapStateToProps = (state) => {
return {
}
}
class SideMenu extends React.Component {
static navigationOptions = ({navigation}) => {
const { state, setParams } = navigation;
return {
headerTintColor: 'red',
headerLeft: null,
headerStyle: { backgroundColor: 'rgba(77, 90, 139, 1)', shadowColor: 'transparent', borderBottomWidth: 0},
};
};
constructor(props) {
super(props);
this._navigateAction = this._navigate.bind(this);
}
_navigate(route) {
let resetAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({routeName: route.id})
]
});
this.props.navigation.dispatch(resetAction)
}
_renderIcon() {
// if (RkTheme.current.name === 'light')
// return <Image style={styles.icon} source={require('../../assets/images/smallLogo.png')}/>;
// return <Image style={styles.icon} source={require('../../assets/images/smallLogoDark.png')}/>
}
handlePress = (route, index) => {
const { navigation } = this.props;
navigation.navigate(route.id);
}
render() {
let menu = MainRoutes.map((route, index) => {
return (
<TouchableHighlight
style={styles.container}
key={route.id}
underlayColor={RkTheme.current.colors.button.underlay}
activeOpacity={1}
onPress={() => this.handlePress(route, index)}>
<View style={styles.content}>
<View style={styles.content}>
<MaterialCommunityIcons size={25} style={{color: 'white'}} name={route.icon} />
<View style={{flex: 1, alignItems: 'left', paddingLeft: 15}}>
<RkText style={{color:'white'}}>{route.title}</RkText>
</View>
</View>
</View>
</TouchableHighlight>
)
});
return (
<View style={styles.root}>
<ScrollView
showsVerticalScrollIndicator={false}>
<View style={[styles.container, styles.content], {borderTopWidth: 0}}>
{this._renderIcon()}
</View>
{menu}
</ScrollView>
</View>
)
}
}
let styles = RkStyleSheet.create(theme => ({
container: {
height: 80,
paddingHorizontal: 16,
borderTopWidth: StyleSheet.hairlineWidth,
borderColor: 'white',
backgroundColor: 'rgba(77, 90, 139, 1)'
},
root: {
paddingTop: Platform.OS === 'ios' ? 20 : 0,
backgroundColor: 'rgba(77, 90, 139, 1)'
},
content: {
flex: 1,
flexDirection: 'row',
alignItems: 'center'
},
icon: {
marginRight: 13,
}
}));
export default connect(mapStateToProps)(SideMenu);
As you can see I do set the style of the header in the NavigationOptions like I do with the other components but the header stays the same colour.
Could this be because the DrawerNavigator is nested within a TabNavigator?
Thanks and really appreciate any help.
The Navigators are defined as so:
onst SettingsDrawerNavigator = DrawerNavigator(
{
SettingsScreen: {
screen: SettingsScreen
}
},
{
//initialRouteName: 'SettingsScreen',
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
contentComponent: (props) => <SideMenu {...props}/>
}
);
export default TabNavigator(
//Adds elements to the navigator at the bottom.
{
//Other tabs.
Account: {
screen: SettingsDrawerNavigator,
}
},
{
navigationOptions: ({ navigation }) => ({
initialRouteName: 'Home',
tabBarIcon: ({ focused }) => {
const { routeName } = navigation.state;
let iconName;
return (
// <Button badge vertical>
// <Badge ><Text>51</Text></Badge>
<Ionicons
name={iconName}
size={24}
style={{ marginBottom: -3 }}
color={focused ? Colors.tabIconSelected : Colors.tabIconDefault}
/>
// </Button>
);
},
}),
tabBarOptions: {
inactiveBackgroundColor: 'transparent',
activeBackgroundColor: 'transparent',
showLabel: false,
style: {
backgroundColor: '#4d5a8b',
}
},
tabBarComponent: TabBarBottom,
tabBarPosition: 'bottom',
animationEnabled: false,
swipeEnabled: false
}
);
Adding a header to the DrawerNavigator resulted in the following (red). I'm trying to set the white background at the top to red.

How to re-render a tab in React-Native

I have a React-Native flashcard app that boots with two tabs, a Home tab, and a New Deck tab. The Home tab is the default, and you can press or swipe over to the New Deck tab.
The Home tab displays all of the decks the user currently has saved.
On the New Deck tab, I have the user enter the title of their new deck and press a submit button. When that submit button is pressed, I re-navigate to the Home tab.
My issue is: How in the world do I trigger a re-render on the Home tab from a button press on the New Deck tab so the user can see the deck they just created?
I know I could use Redux to solve this issue, but no other part of the app is optimized in a "Redux" fashion, and I'd really like to not redesign the architecture of my app for the sole purpose of updating a single screen, mostly because this is the only instance where I would need this ability.
I've attempted to get around this by passing screenProps containing the this.forceUpdate method all the way from the StackNavigator component, but it didn't work. I also tried manually update the state of the App component to trigger a re-render, but the re-render never happened (although the state did update).
App.js
import React, { Component } from 'react'
import { Text, View } from 'react-native'
import AlphaHome from './Components/Home/AlphaHome'
import AlphaQuiz from './Components/Quiz/AlphaQuiz'
import AlphaNewUdaciDeck from './Components/NewUdaciDeck/AlphaNewUdaciDeck'
import AlphaNewUdaciCard from './Components/NewUdaciCard/AlphaNewUdaciCard'
import AlphaUdaciDeckDetails from './Components/UdaciDeckDetails/AlphaUdaciDeckDetails'
import { TabNavigator, StackNavigator } from 'react-navigation'
const Tabs = TabNavigator({
Home: {
screen: AlphaHome,
navigationOptions: {
tabBarLabel: 'Home',
},
},
NewDeck: {
screen: AlphaNewUdaciDeck,
navigationOptions: {
tabBarLabel: 'New Deck',
}
}
}, {
navigationOptions: {
header: null,
},
tabBarOptions: {
activeTintColor: 'white',
indicatorStyle: {
backgroundColor: 'white'
},
style: {
height: 50,
borderBottomColor: 'white',
backgroundColor: 'deepskyblue',
}
},
})
const Stack = StackNavigator({
Home: {
screen: Tabs,
},
AlphaNewUdaciDeck: {
screen: AlphaNewUdaciDeck,
navigationOptions: {
headerTintColor: 'white',
headerStyle: {
backgroundColor: 'deepskyblue'
}
}
},
AlphaNewUdaciCard: {
screen: AlphaNewUdaciCard,
navigationOptions: {
headerTintColor: 'white',
headerStyle: {
backgroundColor: 'deepskyblue'
}
}
},
AlphaUdaciDeckDetails: {
screen: AlphaUdaciDeckDetails,
navigationOptions: {
headerTintColor: 'white',
headerStyle: {
backgroundColor: 'deepskyblue'
}
}
},
})
export default class App extends Component {
render() {
return (
<Stack />
)
}
}
Home.js
import React, { Component } from 'react'
import { ScrollView, View, Text, StyleSheet, AsyncStorage, ActivityIndicator } from 'react-native'
import UdaciDeck from '../Reusable/UdaciDeck'
import { getAllData } from '../../utils/AsyncApi'
export default class HomeExistingUser extends Component {
state = {
decks: null,
}
componentDidMount() {
let decks = getAllData()
setTimeout(() => {
this.setState({
decks
})
}, 1000)
}
showDetails = (title, count) => {
this.props.navigation.navigate('AlphaUdaciDeckDetails', {title, count})
}
render() {
const {decks} = this.state
return (
decks
? <ScrollView contentContainerStyle={styles.container}>
{decks.map(s => <UdaciDeck key={s[1].title} name={s[1].title} count={s[1].questions.length} method={this.showDetails} />)}
</ScrollView>
: <View style={[styles.container, {flex: 1, justifyContent: 'center'}]}>
<ActivityIndicator size='large' color='white' />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
minHeight: '100%',
backgroundColor: 'lightskyblue',
paddingTop: 20,
paddingBottom: 20,
alignItems: 'center',
},
})
NewDeck.js
import React, { Component } from 'react'
import { View, Text, TextInput, StyleSheet, AsyncStorage, TouchableNativeFeedback, Alert } from 'react-native'
import { addDeck } from '../../utils/AsyncApi'
// BUG: when adding a new deck (if HomeExistingUser is true) view doesn't update. Need to figure out a way to update on tab navigate back
export default class AlphaNewUdaciDeck extends Component {
state = {
input: '',
keys: null,
}
componentDidMount() {
AsyncStorage.getAllKeys()
.then(keys => this.setState({
keys
}))
}
handleSubmit = () => {
const {input, keys} = this.state
input.search(' ') > 0 || input.length < 1 || keys.filter(s => s === input).length > 0
? Alert.alert(`Please enter a valid name (${input.length < 1 || keys.filter(s => s === input).length > 0 ? `you can't save a deck with ${input.length < 1 ? 'no' : 'an already used'} name` : "no spaces"})`)
: addDeck(input)
;if(input.search(' ') < 0 || input.length > 0 || keys.filter(s => s === input).length < 1) {
this.props.navigation.goBack()
}
}
render() {
return (
<View style={[styles.container, styles.containerOne]}>
<View style={styles.containerTwo}>
<Text style={styles.text}>Name of the deck</Text>
<Text style={styles.text}>(Please no spaces)</Text>
<TextInput
autoFocus={true}
onChangeText={(input) => this.setState({
input
})}
selectionColor={'deepskyblue'}
underlineColorAndroid={'transparent'}
style={styles.input}
/>
<TouchableNativeFeedback onPress={this.handleSubmit}>
<View style={styles.btn}>
<Text style={styles.btnText}>Save Deck</Text>
</View>
</TouchableNativeFeedback>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'lightskyblue',
},
containerOne: {
alignItems: 'center',
},
containerTwo: {
marginTop: 50,
},
text: {
color: 'white',
fontSize: 20,
},
input: {
backgroundColor: 'white',
height: 50,
width: 300,
marginTop: 15,
fontSize: 20,
paddingLeft: 5,
paddingRight: 5,
color: 'deepskyblue'
},
btn: {
backgroundColor: 'deepskyblue',
marginTop: 50,
padding: 20,
paddingLeft: 50,
paddingRight: 50,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 5,
},
btnText: {
color: 'white',
},
})
You should check out react-navigation-is-focused-hoc at https://github.com/pmachowski/react-navigation-is-focused-hoc to solve the specific problem you mentioned.
You can also try
onNavigationStateChange(prevState, newState)
there is a sample at How can I tell if the screen is navigated to with ReactNavigation

Categories

Resources