How to re-render import component on state change - react-native

I have made two component (parent & child) & import the child component containing react-native modal
I have render child component after state change, it renders first time but on second time, it doesn't work.
Parent.js file is as follows:
import react, {Component} from 'react';
import { View, Text, TouchableOpacity} from 'react-native';
import ActionModal from './ActionModal';
export default class Parent extends Component {
constructor(props){
super(props);
this.state = { tabclicked: false }
}
actiontabclicked = () => {
this.setState({ tabclicked: true });
}
render(){
return (
<View>
<TouchableOpacity onPress={() => { this.actiontabclicked()} }>
<Text> MOVE</Text>
</TouchableOpacity>
{ (this.state.tabclicked) ? <ActionModal /> : null }
</View>
)
}
}
ActionModal.js file code
import React, {Component} from 'react';
import {Modal, Text, TouchableHighlight, View, Alert} from 'react-native';
export default class ActionModal extends Component {
constructor(){
super();
this.state = { modalVisible: true }
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View style={{marginTop: 22}}>
<Modal
animationType="slide"
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => { this.setModalVisible(!this.state.modalVisible)}}>
<View style={{marginTop: 22}}>
<View>
<Text>Hello World!</Text>
</View>
</View>
</Modal>
</View>
);
}
}
ActionModal opens first time but not second time, I think this is because state becomes true but after close modal it doesn't reset.
How can I achieve that ? Thanks in advance

You're not being so clear with what you want to achieve, if you want to achieve this behaviour of tapping > dismiss > tap again > shows
you should make something like this on your setModalVisible function:
setModalState = () => {
this.setState(prevState => ({
modalVisible: !prevState.modalVisible
})
}
This will change the state opposite to what it was. If you want to have more control maybe you can create two functions setModalOpen and setModalClosed
Maybe you can use props on the child component when onRequestClose is triggered to pass this function to the parent and there you can call setModalClosed, the way you have to do it is to make a callback with the given props (look for passing props to parent in react on the internet, it's quite simple)
Hope I could help

Related

Navigation.getParam is undefined while trying to pass function as parameter

I'm trying to use a function from my Main component in my details component which I user react navigation to navigate to and I want to save some changes in detail screen in my main component
//Main.js
import React from 'react';
import {
StyleSheet ,
Text,
View,
TextInput,
ScrollView,
TouchableOpacity,
KeyboardAvoidingView,
AsyncStorage
} from 'react-native'
import Note from './Note'
import { createStackNavigator, createAppContainer } from "react-navigation";
import Details from './Details';
export default class Main extends React.Component {
static navigationOptions = {
title: 'To do list',
headerStyle: {
backgroundColor: '#f4511e',
},
};
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: ''
};
}
render() {
let notes = this.state.noteArray.map((val,key) => {
return <Note key={key} keyval={key} val={val}
goToDetailPage= {() => this.goToNoteDetail(key)}
/>
});
const { navigation } = this.props;
return(
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<Details saveEdit={this.saveEdit} />
</View>
);
}
goToNoteDetail=(key)=>{
this.props.navigation.navigate('DetailsScreen', {
selectedTask: this.state.noteArray[key],
saveEdit: this.saveEdit
});
}
saveEdit = (editedTask,dueDate) => {
this.state.noteArray.push({
'creationDate': editedTask['creationDate'],
'taskName': editedTask['taskName'],
'dueDate': dueDate
});
this.setState({noteArray:this.state.noteArray})
this.saveUserTasks(this.state.noteArray)
}
this.setState({noteArray:this.state.noteArray})
this.saveUserTasks(this.state.noteArray)
}
}
Then I try to use it as prop in my Detail.js
import React from 'react';
import {
StyleSheet ,
Text,
View,
TextInput,
Button,
TouchableOpacity,
} from 'react-native'
import { createStackNavigator, createAppContainer } from "react-navigation";
export default class Details extends React.Component {
constructor(props){
super(props);
this.state = {
dueDate = ''
}
}
static navigationOptions = {
headerStyle: {
backgroundColor: '#f4511e',
},
};
componentDidMount = () => {
this.getUserTasks()
}
render() {
const { navigation } = this.props;
const selectedTask = navigation.getParam('selectedTask', 'task');
var { saveEdit} = this.props;
return(
<View key={this.props.keyval} style={styles.container}>
<View style = { styles.info}>
<Text style= {styles.labelStyle}> Due date:
</Text>
<TextInput
onChangeText={(dueData) => this.setState({dueData})}
style={styles.textInput}
placeholder= {selectedTask['dueDate']}
placeholderTextColor='gray'
underlineColorAndroid = 'transparent'
>
</TextInput>
</View>
<TouchableOpacity onPress={this.props.saveEdit(selectedTask, this.state.dueDate)} style={styles.saveButton}>
<Text style={styles.saveButtonText}> save </Text>
</TouchableOpacity>
</View>
);
}
}
I searched a lot to find the solution and I tried many of them but get different undefined errors. This is not what I did in the first place but when I search I found this solution here. And I know it causes lots of issues.
I want to know how can I manage to access to main method from details and pass parameters to it or how can I manage to use main props in my details component
If you are using react-navigation 5, params is no longer under the navigation object but under route object. This is the link to the sample code:
https://reactnavigation.org/docs/params
Solution
<Details saveEdit={this.saveEdit} />
to
<Details navigation={this.props.navigation} saveEdit={this.saveEdit} />
render() {
return(
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<Details navigation={this.props.navigation} saveEdit={this.saveEdit} />
</View>
);
}
Why?
You are using your Details component in Main screen. So you need to give navigation to Details's props from your Main to use navigation props in Details component.
Because your Details component is not the screen component registered in your navigator(router).
I tried to run your code on my machine but it seems you have too many syntax error in your code (maybe because of copy pasta?)
but it seems you should change
<TouchableOpacity onPress={this.props.saveEdit(selectedTask, this.state.dueDate)}
in Detals.js to
<TouchableOpacity onPress={this.props.navigation.getParams('saveEdit')(selectedTask, this.state.dueDate)}
for clarification this worked for me
in MainPage.js
_test(){
console.log('test');
}
.
.
.
<ActionButton
buttonColor="rgba(231,76,60,1)"
onPress={() => NavigationService.navigate('AddNewSession', {test: this._test})}>
</ActionButton>
and in AddNewSession.js
componentDidMount()
let test = this.props.navigation.getParam('test');
test();
}
There are many mistakes within your codes. First of all you are importing the navigation build-in function {createStackNavigator} in all your files, Main.js and Details.js :
import { createStackNavigator, createAppContainer } from
"react-navigation";
That make me think that you didn't know how the stack navigation or navigation in general functions in react native. You should have a file that handles your routes configuration, let call it MyNavigation.js and then define the routes 'Main' and 'details' in MyNavigations,js. It's only inside MyNavigation.js that you can import "createStackNavigator". Then you will define your functions to move between the screens "Main" and "detail". Those functions will be passed as props to the routes when moving between one another. The overall action wihtin MyNavigation.js will look like:
import React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import Main from './Main';
import Detail from './Detail';
const Stack = createStackNavigator();
function goToDetailFromMainScreen(){
return(this.props.navigation.navigate('switch2'));
}
function DetailSaves(){
return(//your code here to save details);
}
//Here you pass the functions to Main Component to handele Detail componets
's actions
function switch1(){
return(<Main GoToDetails={() => this.goTodetailFromMainScreen()} paramsForDetailActions={() => this.detailSaves()} />)
}
function switch2(){
return(<Details />)
}
export default function MyNavigation() {
return(
<NavigationContainer>
<Stack.Navigator initialRouteName='switch1'>
<Stack.Screen name='switch1' options={{header:()=>null}} component={Main} />
<Stack.Screen name='switch2' options={{headerTitle:"Detail"}} component={Detail} />
</Stack.Navigator>
</NavigationContainer>
)
}
Now inside Main.js you check the props functions passed to it from MyNavigation.js:
// Main.js
constructor(props){
super(props);
}
goToDetails = () => {
this.props.onPress?.();
}
paramsForDetailActions= () => {
this.props.onPress?.();
}

change view in react native (0.5)

I have 2 views and I want to move from the first one to the second one without using createStackNavigator
There´s no need to use navigation because the first view is just a welcome screen
import React from 'react';
import { View, Text, Button } from 'react-native';
class HomeScreen extends React.Component {
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Text>Welcome!</Text>
<Button
title="sign In"
onPress={() => navigate('SignInScreen')}
/>
</View>
);
}
}
class SignInScreen extends React.Component {
render() {
return (
<View>
<Text>Sign In screen</Text>
</View>
);
}
}
export default HomeScreen
the error I´m getting is
TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate')
thank you.
Use a flag on state. When you click the button on HomeScreen, it will change the flag to true, which will allow the conditional statement to call the SignInScreen to be rendered.
import React from 'react';
import { View, Text, Button } from 'react-native';
class HomeScreen extends React.Component {
state = {
loggedIn: false,
};
render() {
const { navigate } = this.props.navigation;
return this.loggedIn ? (
<SignInScreen />
) : (
<View>
<Text>Welcome!</Text>
<Button
title="sign In"
onPress={() => this.setState({ loggedIn: true })}
/>
</View>
);
}
}
class SignInScreen extends React.Component {
render() {
return (
<View>
<Text>Sign In screen</Text>
</View>
);
}
}
export default HomeScreen;

How to setState without using .bind(this) in react-native?

I have no idea How to set state.
Below is my code...
import React from 'react';
import { StyleSheet, Text, View, TouchableHighlight, AsyncStorage, ListView } from 'react-native';
export default class App extends React.Component {
constructor(){
super();
this.state = {
myLeader: 'Joe',
};
}
setMyLeader(name){
this.setState({
myLeader: name
});
}
render() {
return (
<View>
<TouchableHighlight
style={{padding: 30}}
onPress={this.setState(myLeader: 'xxx')}
>
<Text>foo</Text>
</TouchableHighlight>
</View>
);
}
}
error message is this. 'Can't find variable: myLeader'
How to fix this problem?
Inside your onPress function you can:
a) directly set the state
onPress={() => this.setState({ myLeader: 'xxx' })}
b) call your setLeader function
onPress={() => this.setMyLeader('xxx')}

NavigatorIOS problems

Hi I'm having some trouble using the NavigatorIOS in my app, it gives me the error:'undefined is not an object(evaluating 'this.props.navigator.push').
I tried to see some examples but I can't see the error, can someone help me?
Here is the code:
import React, { Component, PropTypes } from 'react';
import Dimensions from 'Dimensions';
import Menu from './Menu'
import {
AppRegistry,
StyleSheet,
Image,
TouchableHighlight,
NavigatorIOS,
FadeInView,
Text,
View
} from 'react-native';
class Home extends React.Component {
constructor(props, context) {
super(props, context);
this.onForward = this.onForward.bind(this);
}
onForward(Menu){
this.props.navigator.push({
component: Menu,
title: "Menu",
navigationBarHidden: true,
});
}
render() {
return (
<View style={styles.container}>
<Image
style={styles.img}
source={require('./img/scrittaNera.png')}
onLoadStart={(e) => this.setState({loading: true})}
/>
<TouchableHighlight style={styles.button} onPress={() => this.onForward()}>
<Text style={styles.buttonText}>Get Inspired</Text>
</TouchableHighlight>
</View>
);
}
}
Thanks
You need to bind the function to your Component in this case this can be done as follows:
<TouchableHighlight
style={styles.button}
onPress=this.onForward.bind(this)>
....
</TouchableHighlight>
Also you need to make sure your main component is wrapped inside a <NavigatorIOS> component. Such as:
import React, { Component, PropTypes } from 'react';
import { NavigatorIOS, Text } from 'react-native';
export default class NavigatorIOSApp extends Component {
render() {
return (
<NavigatorIOS
initialRoute={{
component: MyScene,
title: 'My Initial Scene',
}}
style={{flex: 1}}
/>
);
}
}

Passing imported View in renderNavigationView of DrawerLayoutAndroid

Trying to load partial view inside my drawer but instead, I'm getting blank page.
Can anybody guide me with this;
MainScreen.js
..
import DrawerContent from "./PartialViews/DrawerContent";
...
render() {
return (
<DrawerLayoutAndroid
style={mainStyles.applicationView}
drawerWidth={300}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => {
<DrawerContent onItemClick={this._change.bind(this)} />;
}}
ref={_drawer => this.drawer = _drawer}
>
DrawerContent.js
import React, { Component } from "react";
import {
View,
Text,
Image,
ScrollView,
TouchableOpacity
} from "react-native";
import drawerStyles from "../Styles/DrawerContentStyles";
export default class DrawerContent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={drawerStyles.container}>
...
</View>
)}
I'm new to react-native development and was also struggling with this same issue, this is how I solved it:
const Drawer = (mainscreen) => {
return (
<View>
...
</View>
);
}
export default Drawer;
then within your MainScreen you can call it and pass in you context
<DrawerLayoutAndroid
ref={'DRAWER'}
drawerWidth={300}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => Drawer(this)}
>
Not sure if this is the right approach, but it works.
Hope this helps