I have an infinite loop that seems to be occurring when I use react-redux. I use Navigation Experimental which loads connectRouteScreen as the scene to be rendered through NavigationCardStack. I'm using RN 0.30. But also could reproduce this in 0.31-rc.0
[...]
Use Navigation Experimental to transition and load connectRouteScreen as a Scene
export default function connectRouteScreen(Scene, sceneProps){
class RouteScreen extends React.Component{
[...]
render() {
const { navigator, pathVariables } = this.props;
return (
<View style={styles.container}>
<Scene
navigator={navigator}
{...pathVariables.toJS()}
/>
</View>);
}
}
RouteScreen.propTypes = {...RouteScreenPropTypes};
const routeScreenProperties = extractSceneRendererProps(sceneProps);
/*return <Scene
navigator={routeScreenProperties.navigator}
{...routeScreenProperties.pathVariables.toJS()}
/>;
*/
return <RouteScreen
{...routeScreenProperties}
/>;
}
LoadingScreen is loaded as "Scene".
#connect(
() => {return {}},
(dispatch) => {
return {
loginActions: bindActionCreators(loginActions, dispatch),
}
})
export default class LoadingScreen extends React.Component {
constructor(props){
super(props);
}
shouldComponentUpdate(nextProps){
return false;
}
componentDidMount(){
const { navigator } = this.props;
this.props.loginActions.executeLoginFlow();
}
render() {
const Animatable = require('react-native-animatable');
return (
<Animatable.View
animation="pulse"
easing="ease-out"
iterationCount="infinite"
style={localStyle.container}>
<Icon name="logo" style={localStyle.iconStyle} size={150}/>
</Animatable.View>
);
}
};
So, If I return the Scene directly instead of RouteScreen, no problem.
If I remove the #connect syntax and escape this.props.loginActions..., no problem.
If I return RouteScreen and remove everything it does and just return the Scene => infinite loop.
Does anybody have any suggestions how to deal with this?
Related
NetInfo is used to check the connection & theres a checkNetwork function called in onPress of TouchableOpacity. When the button is clicked once, the checkNetwork
function is called automatically multiple times without tapping the button when the network connection is lost and vice versa.
Please have a look at the code here:
Please have a look at the video
export default class App extends React.Component {
checkNetwork = () => {
NetInfo.addEventListener((state) => {
if (state.isConnected) {
alert('isConnected');
} else {
alert('not connected');
}
});
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity
activeOpacity={0.8}
onPress={()=> this.checkNetwork()}>
<Text>Check here</Text>
</TouchableOpacity>
</View>
);
}
}
You should not declare event listener inside of the click itself,
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {alert: ''};
}
componentDidMount() {
NetInfo.addEventListener((state) => this.setState({ alert: state.isConnected ? 'isConnected' : 'not connected'})
}
checkNetwork = () => alert(this.state.alert)
render() {
return (
<View style={styles.container}>
<TouchableOpacity
activeOpacity={0.8}
onPress={()=> this.checkNetwork()}>
<Text>Check here</Text>
</TouchableOpacity>
</View>
);
}
}
though in your case event listener isn't exactly the fit logic for UI behavior of pressing button, so I think you might wanna use useNetInfo
import {useNetInfo} from "#react-native-community/netinfo";
class App extends React.Component {
checkNetwork = () => {
if (this.props.netInfo.isConnected) {
alert('isConnected');
} else {
alert('not connected');
}
});
};
...rest render...
}
export default () => <App netInfo={useNetInfo()} />
I'm currently working on an app in React-Native and it includes DrawerNavigation, SwitchNavigation and AppContainer. There is a method at header.js that i need to use in order to make the drawer functionable (toggleDrawer())
I've tried passing the function at the DrawerNavigator but it didnt work.
export default class Header extends React.Component {
render() {
return (
<View style={styles.container}>
<TouchableOpacity
onPress={() => {
this.props.navigation.toggleDrawer();
}}
>
<Image
source={require("/Users/Rron/AnketaApp/assets/hamburger-
icon.jpg")}
style={styles.imageStyle}
/>
</TouchableOpacity>
</View>
);
}
}
});
export default class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
let drawerLabel = "Home";
return { drawerLabel };
};
render() {
return (
<View style={styles.container}>
<Header {...this.props}/>
<ScrollView>
<Content />
</ScrollView>
</View>
);
}
}
export default class DrawerNavigator extends React.Component {
render() {
return <AppContainer />;
}
}
const AppDrawerNavigator = createDrawerNavigator(
{
Home: {
screen: HomeScreen
},
Anketa: {
screen: AnketaScreen
}
}
);
const AppContainer = createAppContainer(
createSwitchNavigator({
Introduction: {
screen: IntroductionScreen
},
Drawer: {
screen: AppDrawerNavigator``
}
})
);
The error says
this.props.navigation.toggleDrawer is not a function and its not
defined.
What you can do is import { DrawerActions } from 'react-navigation-drawer' and use it as it says in the docs.
this.props.navigation.dispatch(DrawerActions.toggleDrawer());
Also make sure that you components are inside the navigation.
I have a Main class which I show an array to user, then in detail page user can edit each element which I'm passing using react navigation parameter. I want to edit my array in the detail class and save it using async storage.
//Main.jsimport React from 'react';
import {
StyleSheet ,
Text,
View,
TextInput,
ScrollView,
TouchableOpacity,
KeyboardAvoidingView,
AsyncStorage
} from 'react-native'
import Note from './Note'
import detail from './Details'
import { createStackNavigator, createAppContainer } from "react-navigation";
export default class Main extends React.Component {
static navigationOptions = {
title: 'To do list',
headerStyle: {
backgroundColor: '#f4511e',
},
};
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
dueDate: ''
};
}
async saveUserTasks(value) {
try {
await AsyncStorage.setItem('#MySuperStore:userTask',JSON.stringify(value));
} catch (error) {
console.log("Error saving data" + error);
}
}
getUserTasks = async() =>{
try {
const value = await AsyncStorage.getItem('#MySuperStore:userTask');
if (value !== null){
this.setState({ noteArray: JSON.parse(value)});
}
} catch (error) {
console.log("Error retrieving data" + error);
}
}
render() {
this.getUserTasks()
let notes = this.state.noteArray.map((val,key) => {
return <Note key={key} keyval={key} val={val}
deleteMethod={ () => this.deleteNote(key)}
goToDetailPage= {() => this.goToNoteDetail(key)}
/>
});
const { navigation } = this.props;
return(
<KeyboardAvoidingView behavior='padding' style={styles.keyboard}>
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<View style={styles.footer}>
<TextInput
onChangeText={(noteText) => this.setState({noteText})}
style={styles.textInput}
placeholder='What is your next Task?'
placeholderTextColor='white'
underlineColorAndroid = 'transparent'
>
</TextInput>
</View>
<TouchableOpacity onPress={this.addNote.bind(this)} style={styles.addButton}>
<Text style={styles.addButtonText}> + </Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
);
}
addNote(){
if (this.state.noteText){
var d = new Date();
this.state.noteArray.push({
'creationDate': d.getFullYear() + "/" + (d.getMonth()+1) + "/" + d.getDay(), 'taskName': this.state.noteText,'dueDate':'YYYY/MM/DD'
});
this.setState({noteArray:this.state.noteArray})
this.setState({noteText: ''});
this.saveUserTasks(this.state.noteArray)
}
}
deleteNote(key){
this.state.noteArray.splice(key,1);
this.setState({noteArray: this.state.noteArray})
this.saveUserTasks(this.state.noteArray)
}
goToNoteDetail=(key)=>{
this.props.navigation.navigate('DetailsScreen', {
selectedTask: this.state.noteArray[key],
});
}
}
in detail view I have this method which is similar to add note in main class:
export default class Details extends React.Component {
render() {
const { navigation } = this.props;
const selectedTask = navigation.getParam('selectedTask', 'task');
return(
<View key={this.props.keyval} style={styles.container}>
<TouchableOpacity onPress={this.saveEdit.bind(this)} style={styles.saveButton}>
<Text style={styles.saveButtonText}> save </Text>
</TouchableOpacity>
</View>
);
}
saveEdit(){
let selectedItem = { 'creationDate': selectedTask['creationDate'],
'taskName': selectedTask['taskName'],
'dueDate': this.state.dueData}
this.props.navigation.state.params.saveEdit(selectedItem)
}
}
How can I change my props in any component?
First of all you shouldn't call this.getUserTasks() in the render method because the function has this.setState which is bad and could end in a endless loop I guess or at least effect in worse performance. You could instead call it in componentDidMount:
componentDidMount = () => {
this.getUserTasks();
}
Or alternatively call already in constructor but I prefer the first option:
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
dueDate: ''
};
this.getUserTasks()
}
this.props.noteArray.push({.. is probably undefined because you aren't passing it down any where. (Didn't see any reference in your snippet). I guess I would implement the saveEdit function in the Main.js component and simply pass it down to the navigation route and call the function in Details component by accessing the navigation state props:
Update
goToNoteDetail=(key)=>{
this.props.navigation.navigate('DetailsScreen', {
// selectedTask: this.state.noteArray[key],
selectedItem: key,
saveEdit: this.saveEdit
});
}
saveEdit(selectedItem){
const selectedTask = this.state.noteArray[selectedItem]
this.state.noteArray.push({
'creationDate': selectedTask['creationDate'],
'taskName': selectedTask['taskName'],
'dueDate': this.state.dueData
});
this.setState({noteArray:this.state.noteArray})
this.setState({dueData: 'YYYY/MM/DD'});
this.saveUserTasks(this.state.noteArray)
}
And then call saveEdit in Details Component:
saveSelectedItem = () => {
const { navigation } = this.props.navigation;
const {selectedItem, saveEdit} = navigation.state && navigation.state.params;
saveEdit(selectedItem)
}
I am learning react-native navigation https://reactnavigation.org/docs/intro/ . I see in examples there
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
}
I could not understand what exactly this line of code is for const { navigate } = this.props.navigation;
syntax has nothing to do with React Native
it is called Destructuring assignment in es6 / es2015
const { navigate } = this.props.navigation;
is equivilent to with exception to var and const .
var navigate = this.props.navigation.navigate
the example without Destructuring should look like this
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
return (
<View>
<Text>Hello, Chat App!</Text>
<Button
onPress={() => this.props.navigation.navigate('Chat')}
title="Chat with Lucy"
/>
</View>
);
}
}
Include on your ServiceAction the this.props.navigation something like this:
<HomeScreen navigation={this.props.navigation}/>
because the props.navigation are by default on your parent component
and on HomeScreen component you will access to navition like:
..
goToSignUp() {
this.props.navigation.navigate('SignUp');
}
..
For me also was confusing before. Cheers!
I have been following this tutorial, however, when I go to run the application after dropping the code in, it doesn't seem to work. The tutorial seems fairly simple, so I can not understand why it is not working.
The error message I'm getting is:
import React from 'react'
import { View, Text, StyleSheet, Image, Share } from 'react-native'
class ShareLesson extends Component {
constructor(props) {
super(props);
this._shareMessage = this._shareMessage.bind(this);
this._showResult = this._showResult.bind(this);
this.state = { result: ''};
}
_showResult(result) {
this.setState({result});
}
_shareMessage() {
Share.share({
message: 'This is a simple shared message'
}).then(this._showResult);
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={this._shareMessage}>
<Text style={styles.welcome}>
Share
</Text>
</TouchableHighlight>
<Text>
{JSON.stringify(this.state.result)}
</Text>
<View>);
}
}
Tabs Component
class Tabs extends Component {
_changeTab (i) {
const { changeTab } = this.props
changeTab(i)
}
_renderTabContent (key) {
switch (key) {
case 'today':
return <Home />
case 'share':
return <Share />
case 'savequote':
return <SaveQuote />
case 'moremenu':
return <MoreMenu />
}
}
render () {
const tabs = this.props.tabs.tabs.map((tab, i) => {
return (
<TabBarIOS.Item key={tab.key}
icon={tab.icon}
selectedIcon={tab.selectedIcon}
title={tab.title}
onPress={() => this._changeTab(i)}
selected={this.props.tabs.index === i}>
{this._renderTabContent(tab.key)}
</TabBarIOS.Item>
)
})
return (
<TabBarIOS tintColor='black'>
{tabs}
</TabBarIOS>
)
}
}
export default Tabs