React Native: setState triggers unwanted Tab change in Tab Navigator - reactjs

Something does not make sense with my code.
I am using React Native to create a app.
In that app I am using a Tab Navigator.
It works fine until I call this.setState which for some reason triggers a unwanted Tab change from one tab to the other.
Why would setState trigger a Tab change??
This is my code:
import React from 'react';
import { StyleSheet, Text, View, FlatList, TextInput, StatusBar, Button } from 'react-native';
import { TabNavigator } from 'react-navigation';
import { Constants } from 'expo'
import { purple, white } from './utils/colors'
const R = require('ramda')
function CustomStatusBar({ backgroundColor, ...props }){
return (
<View style={{backgroundColor, height: Constants.statusBarHeight}}>
<StatusBar translucent backgroundColor={backgroundColor} {...props} />
</View>
)
}
export default class App extends React.Component {
constructor(props){
super(props)
this.handleDeckTitle = this.handleDeckTitle.bind(this)
}
state = {
title: ''
}
renderItem = (sample) => {
console.log('renderItem', sample)
return <Text>SAMPLE DATA</Text>
}
handleDeckTitle(e){
console.log('handleDeckTitle')
console.log('e', e)
console.log('this.state', this.state)
this.setState((prevState, props) => ({
title: e
}));
}
submitDeckTitle(){
console.log('submitDeckTitle')
}
render() {
console.log('R', R)
const Decks = () => {
return (
<View>
<CustomStatusBar backgroundColor={purple} barStyle='light-content' />
<Text>Decks!</Text>
</View>
)
}
const NewDeck = () => {
return (
<View>
<CustomStatusBar backgroundColor={purple} barStyle='light-content' />
<Text>What is the title of your new deck?</Text>
<TextInput style = {styles.input} onChangeText={this.handleDeckTitle}/>
<Button onPress={this.submitDeckTitle} title="Submit" />
</View>
)
}
const Tabs = TabNavigator({
Decks: {
screen: Decks
},
'New Deck': {
screen: NewDeck
},
});
return (
<Tabs />
);
}
}
const styles = StyleSheet.create({
container: {
paddingTop: 23,
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
input: {
margin: 15,
height: 40,
borderColor: '#7a42f4',
borderWidth: 1
},
});
I don't see what is wrong with this code.
In fact I think it should just work normally but it does not.
It triggers a tab change when I call handleDeckTitle which then calls this.setState

Got it to work now.
I changed the part that calls setState to be be a Separate Component with its own state.
Here is the code:
import React from 'react';
import { StyleSheet, Text, View, FlatList, TextInput, StatusBar, Button } from 'react-native';
import { TabNavigator } from 'react-navigation';
import { Constants } from 'expo'
import { purple, white } from './utils/colors'
const R = require('ramda')
function CustomStatusBar({ backgroundColor, ...props }){
return (
<View style={{backgroundColor, height: Constants.statusBarHeight}}>
<StatusBar translucent backgroundColor={backgroundColor} {...props} />
</View>
)
}
const Decks = () => {
return (
<View>
<CustomStatusBar backgroundColor={purple} barStyle='light-content' />
<Text>Decks!</Text>
</View>
)
}
class NewDeck extends React.Component {
constructor(props){
super(props)
this.handleDeckTitle = this.handleDeckTitle.bind(this)
}
state = {
title: ''
}
handleDeckTitle(e){
console.log('handleDeckTitle')
console.log('e', e)
console.log('this.state', this.state)
this.setState((prevState, props) => ({
title: e
}));
}
render(){
return (
<View>
<CustomStatusBar backgroundColor={purple} barStyle='light-content' />
<Text>What is the title of your new deck?</Text>
<TextInput style = {styles.input} onChangeText={this.handleDeckTitle}/>
<Button onPress={this.submitDeckTitle} title="Submit" />
</View>
)
}
}
const Tabs = TabNavigator({
Decks: {
screen: Decks
},
'New Deck': {
screen: NewDeck
},
});
export default class App extends React.Component {
constructor(props){
super(props)
// this.handleDeckTitle = this.handleDeckTitle.bind(this)
}
state = {
title: ''
}
renderItem = (sample) => {
console.log('renderItem', sample)
return <Text>SAMPLE DATA</Text>
}
submitDeckTitle(){
console.log('submitDeckTitle')
}
render() {
console.log('R', R)
return (
<Tabs />
);
}
}
const styles = StyleSheet.create({
container: {
paddingTop: 23,
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
input: {
margin: 15,
height: 40,
borderColor: '#7a42f4',
borderWidth: 1
},
});

Related

React Native Application crashing in iOS

Can anyone please help me to figure out this. I am using Flatlist and Inviewport dependencies for a video player integrated list view. I am facing memory issues but works fine in Android devices. It just crashing on iOS (in high end Android devices with RAM 6 Gig works perfectly)
Error logs
VideoPlayer.js
import React, {Component} from 'react';
import { View, StyleSheet, Dimensions, StatusBar } from 'react-native';
import { Video } from 'expo-av';
import InViewPort from 'react-native-inviewport';
export default class VideoPlayer extends React.Component {
pauseVideo = () => {
if(this.video) {
this.video.pauseAsync();
}
}
stopVideo = () => {
if(this.video) {
this.video.stopAsync();
}
}
playVideo = () => {
if(this.video) {
this.video.playAsync();
}
}
handlePlaying = (isVisible) => {
isVisible ? this.playVideo() : this.stopVideo();
}
render() {
//console.log(this.props);
return (
<View style={styles.container}>
<InViewPort onChange={this.handlePlaying}>
<Video
ref={ref => {this.video = ref}}
source={{ uri: 'https://dubaistack.com/beat/'+this.props.url }}
rate={1.0}
volume={1.0}
isMuted={false}
resizeMode="contain"
isLooping={true}
shouldPlay
style={{ width: Dimensions.get('window').width, height: Dimensions.get('window').height - StatusBar.currentHeight, backgroundColor: 'black' }}
/>
</InViewPort>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center'
}
});
ShortVideos.js
import React, {useState} from 'react';
import {
View ,
ScrollView,
StyleSheet ,
Text,
Dimensions,
FlatList,
StatusBar
} from 'react-native';
import VideoPlayer from '../components/VideoPlayer';
function Item(item) {
return (
<VideoPlayer url={item.item.location}/>
);
}
function ShortVideos(props) {
const [loading, setLoading] = useState(true);
const [data, setData] = useState([]);
fetch('https://dubaistack.com/beat/posts/get.php?lvid')
.then((response) => response.json())
.then((responseJson) => {
//console.log(responseJson);
setLoading(false);
setData(responseJson);
})
if(loading){
return(
<Text style={{color:'red'}}>Loading</Text>
);
}else{
return(
<FlatList
data={data}
renderItem={({item}) => <Item item={item} /> }
keyExtractor={item => item.id}
pagingEnabled
/>
);
}
}
const styles = StyleSheet.create({
item: {
height: Dimensions.get('window').height,
width: Dimensions.get('window').width,
backgroundColor: '#336699',
justifyContent: 'center',
alignItems: 'center'
},
title: {
fontSize: 32,
color: 'white',
},
})
export default ShortVideos;
To remove - this warning you need to use componentWillUnmount like this below and rebuild: -
class Home extends Component {
_isMounted = false;
constructor(props) {
super(props);
}
componentDidMount() {
this._isMounted = true;
-----
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
...
}
}

How to set the state from a button inside static navigationoption react-native?

I want to click the TouchableOpacity and set the state true so that will open. I am getting error. and how to align the button in center at the header? alignSelf is not working.
`
import React, {Component} from 'react';
import {
StyleSheet,
SafeAreaView,
View,
TouchableOpacity,
Text,
} from 'react-native';
import Menu from '../../src/components/menubar';
export default class SearchPage extends Component {
constructor(props) {
super(props);
this.state = {isMenubarDisplayed: false};
}
static navigationOptions = {
headerTitle: () => {
return (
<TouchableOpacity
onPress={()=> this.setState({isMenubarDisplayed: true})}>
<Icon name="search" size={20} color="#000" />
</TouchableOpacity>
);
},
headerTitleStyle: {
alignSelf: 'center',
flex: 1,
},
};
render() {
return (
<SafeAreaView style={styles.container}>
{this.state.isMenubarDisplayed ? (
<Menu />
) : null}
</SafeAreaView>
);
}
}`
You need to try this, expo-snack .
This is my below code for search.js ,
import * as React from 'react';
import { Text, View, StyleSheet,TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
import Menu from './menu';
import Icon from 'react-native-vector-icons/FontAwesome';
export default class Search extends React.Component {
constructor(props){
super(props);
this.state={
isMenubarDisplayed: false,
}
}
static navigationOptions = ({ navigation }) => {
return {
headerTitle: () => {
return (
<TouchableOpacity onPress={navigation.getParam('toggleMenu')}>
<Icon name="search" size={20} color="#000" />
</TouchableOpacity>
);
},
};
};
toggleMenu = () => {
this.setState({ isMenubarDisplayed: !this.state.isMenubarDisplayed})
}
renderMenu = () => (
<Menu />
)
componentDidMount(){
this.props.navigation.setParams({
toggleMenu: this.toggleMenu
});
}
render() {
return (
<View style={styles.container}>
{this.state.isMenubarDisplayed?this.renderMenu():<View></View>}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});
Hope it helps. feel free for doubts.
This is all you need https://reactnavigation.org/docs/en/header-buttons.html#header-interaction-with-its-screen-component
static navigationOptions = ({ navigation }) => {
return {
headerTitle: () => {
return (
<View style={{ flex: 1, alignItems: 'center' }}>
<TouchableOpacity onPress={navigation.getParam('toggleMenu')}>
<Icon name="search" size={20} color="#000" />
</TouchableOpacity>
</View>
);
},
};
};
componentDidMount() {
this.props.navigation.setParams({ toggleMenu: this.toggleMenu });
}
toggleMenu = () => {
this.setState({isMenubarDisplayed: true});
}

React Native Navigation with React Native Admob About

I created a 3 page application with React native navigation. Admob ads are on the 3rd page. I want to try the same ad code on all three screens. If there is any idea in this matter, please share. Thank you.
For better understanding I give the following expo code.
import React, { Component } from 'react';
import {
WebView,
AppRegistry,
StyleSheet,
Text,
View,
Button,
Alert
} from 'react-native';
import { StackNavigator } from 'react-navigation';
import ListComponent from './ListComponent';
class App extends Component {
static navigationOptions = {
title: 'App',
};
OpenSecondActivityFunction = () => {
this.props.navigation.navigate('Second');
};
render() {
return (
<View style={styles.container}>
<Button
onPress={this.OpenSecondActivityFunction}
title="Open Second Activity"
/>
</View>
);
}
}
class SecondActivity extends Component {
static navigationOptions = {
title: 'SecondActivity',
};
OpenThirdActivityFunction = data => {
this.props.navigation.navigate('Third');
};
render() {
return (
<View style={{ flex: 1 }}>
<ListComponent
OpenThirdActivityFunction={this.OpenThirdActivityFunction}
/>
</View>
);
}
}
class ThirdActivity extends Component {
static navigationOptions = {
title: 'ThirdSecondActivity',
};
render() {
return (
<View style={{ flex: 1 }}>
<Text>3</Text>
</View>
);
}
}
const ActivityProject = StackNavigator({
First: { screen: App },
Second: { screen: SecondActivity },
Third: { screen: ThirdActivity },
});
export default ActivityProject;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
}
});
Listcomponent.js
import React, { Component } from 'react';
import {
AppRegistry,
View,
Text,
FlatList,
ActivityIndicator,
} from 'react-native';
import { List, ListItem, SearchBar } from 'react-native-elements';
class ListComponents extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
page: 1,
seed: 1,
error: null,
refreshing: false,
};
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '98%',
backgroundColor: '#CED0CE',
marginLeft: '2%',
}}
/>
);
};
renderHeader = () => {
return <SearchBar placeholder="Type Here..." lightTheme round />;
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: '#CED0CE',
}}>
<ActivityIndicator animating size="large" />
</View>
);
};
render() {
return (
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={[{ name: 1, coders: 2 }]}
renderItem={({ item }) => (
<ListItem
roundAvatar
title={`${item.name}`}
subtitle={item.coders}
containerStyle={{ borderBottomWidth: 0 }}
onPress={() => this.props.OpenThirdActivityFunction(item.coders)}
/>
)}
keyExtractor={item => item.coders}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
/>
</List>
);
}
}
export default ListComponents;

React Navigation failed. No errors

I'm trying to navigate from tab page to other page. I'm following tabnavigator and stacknavigator.
myTabsHost(RegisterHostPage) Here I'm hosting two tabs
import React, { Component } from "react";
import {
AppRegistry,
Text,
View,
Image,
StyleSheet,
TouchableOpacity
} from "react-native";
import { TabNavigator } from "react-navigation";
import { Tab } from "../../config/router.js";
import {Tab2} from "../../config/router.js";
import { NavigationActions } from "react-navigation";
class RegisterHost extends Component {
render() {
return (
<View style={Styles.container}>
<Text style={Styles.boldLabel}> User Register</Text>
<Text style={Styles.normalLabel}>Wallet account registration</Text>
<TouchableOpacity
onPress={() => {
const navigateAction = NavigationActions.navigate({
key: null,
routeName: "preactivate",
params: {}
});
this.props.navigation.dispatch(navigateAction);
}}
>
<Text>topreactivate</Text>
</TouchableOpacity>
<Tab2 />
</View>
);
}
}
const Styles = StyleSheet.create({
container: {
flex: 1,
padding: 2,
justifyContent: "center",
backgroundColor: "#FFFFFF"
},
boldLabel: {
fontWeight: "bold",
fontSize: 24,
alignSelf: "center",
color: "#08AE9E",
marginBottom: 20,
marginTop: 10
},
normalLabel: {
fontWeight: "normal",
fontSize: 18,
alignSelf: "center",
color: "black",
marginBottom: 20,
marginTop: 10
}
});
export default RegisterHost;
myTabPage (BankCustomerRegister)
import React, { Component } from "react";
import {
Text,
View,
Image,
StyleSheet,
TextInput,
TouchableOpacity
} from "react-native";
import { TabNavigator } from "react-navigation";
import{StackNavigator} from 'react-navigation';
import FetchData from "../../utils/fetch.js";
class BankCustomerRegister extends Component {
constructor(props) {
super(props);
this.state = {
stCustId: "",
stIdcard: "",
stPhoneNum: "",
isMounted: false
};
}
}
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.container}>
<Image source={require("../../resources/icons/bank.png")} />
<TextInput
style={styles.textInput}
onChangeText={this._handleCustId}
placeholderTextColor="black"
placeholder="Customer ID"
/>
<TextInput
style={styles.textInput}
placeholderTextColor="black"
onChangeText={this._handleIdCard}
placeholder="ID card"
/>
<TextInput
style={styles.textInput}
placeholderTextColor="black"
onChangeText={this._handlePhoneNum}
placeholder="Phone No"
/>
<TouchableOpacity
onPress={() => {
// NOTICE HERE
const navigateAction = NavigationActions.navigate({
routeName: "preactivate",
params: {},
});
this.props.navigation.dispatch(navigateAction);
}}
style={styles.touchable}
>
<Text style={styles.btnlabel}>Register</Text>
</TouchableOpacity>
</View>
);
}
}
export default BankCustomerRegister;
when i click touchable.its supposed to navigate to otherPage, i'ts not navigating anywhere , even no errors.
myOtherPage(preactivate)
import React, { Component } from "react";
import {
View,
Text,
StyleSheet
} from "react-native";
class PreUserActivation extends Component {
// Render callBack
render() {
return (
<View style={styles.container}>
<Text>Screen</Text>
</View>
);
}
}
export default PreUserActivation;
My router config in router.js
//tab Router
export const Tab = TabNavigator(
{
BankCustomerRegister: {
screen: BankCustomerRegister,
navigationOptions: {
tabBarLabel: "Bank Customer"
}
},
nonbankcustomer: {
screen: NonCustomerRegister,
navigationOptions: {
tabBarLabel: "New Customer"
}
}
},
{
tabBarPosition: "top",
animationEnabled: true,
tabBarOptions: {
// activeTintColor: "#e91e63",
labelStyle: {
fontSize: 16
},
style: {
backgroundColor: "#08AE9E"
},
tabStyle: { width: 200 } //Set width to make INLINE TABS
}
}
);
export const Root = StackNavigator({
board: {
screen: OnBoardScreen,
navigationOptions: {
header: null
}
},
preactivate: {
screen: PreUserActivation,
navigationOptions: {
header: null
}
},
Tabs: {
screen: Tab
}
});
Is there something i'm missing.
You need a reset. Use navigate() when navigating from one tab to another in the same TabNavigator for example. In your case, you are navigating to a screen in the parent navigator. Try this instead:
onPress={() => {
const navigateAction = NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'preactivate'})
]
});
this.props.navigation.dispatch(navigateAction);
}}

How to resolve React-Native navigation error for undefined is not an object?

Here's my code. I have tried many different things based on react-navigation and navigators but still getting Undefined is not an object(evaluating _this3.props.navigation.navigate).
I even tried restarting the package manager and running project again.
I am running my project on Android Device.
Please help with relevant lines to my code.
import React, {
Component
} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
Button,
Alert,
} from 'react-native';
import {
StackNavigator,
} from 'react-navigation';
import ProfileScreen from './ProfileScreen'
//import HomeScreen from './HomeScreen'
export const AwesomeProject = StackNavigator({
//Home: {screen: HomeScreen},
Profile: {
screen: ProfileScreen,
navigationOptions : {
title: 'Welcome',
}
},
});
const onButtonPress = () => {
Alert.alert('Button has been pressed!');
};
class Blink extends Component {
constructor(props) {
super(props);
this.state = {
showText: true
};
// Toggle the state every second
setInterval(() => {
this.setState({
showText: !this.state.showText
});
}, 1000);
}
render() {
let display = this.state.showText ? this.props.text : ' ';
return (
<Text> {display} </Text>
);
}
}
export default class HomeScreen extends Component {
constructor(props){
super(props)
}
render() {
//const {navigate} = this.props.navigation;
return (
<View style={styles.container}>
<Text style={styles.welcome}>
<Blink text='Hello!'/>
</Text>
<Button
//onPress = {onButtonPress}
onPress = {() => this.props.navigation.navigate('Profile').bind(this)}
title="Lets Go!"
color="#851884"
accessibilityLabel="Learn more about people">
</Button>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#456987',
},
welcome: {
fontSize: 20,
textAlign: 'center',
color: '#DD5522',
margin: 10,
},
});

Resources