Passing data back to component by react-native navigation - react-native

I have main App.js where i implemented StackNavigator:
export default class App extends Component {
render() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="MainPage" component={MainPage} />
<Stack.Screen name="Submit" component={Submit} />
</Stack.Navigator>
</NavigationContainer>
);
}
}
What i want to do is Pass data from Submit component into my MainPage and display it in ScrollView from array: arr in state of MainPage.
Mainpage looks like this. I want to pass function addNode to adding node into state of my MainPage:
class MainPage extends Component {
constructor(props) {
super(props);
this.state = {
arr: [],
liters: '',
time: '',
};
}
addNode = (time, liters) => {
if (this.state.time) {
this.state.arr.push({calc: time + liters});
this.setState({time: ''});
this.setState({liters: ''});
}
};
onPress = () => {
this.props.navigation.navigate('Submit', {addNode: this.addNode});
};
render() {
return (
<View>
<ScrollView>{this.state.arr}</ScrollView>
<TouchableOpacity onPress={this.onPress}>
<Text>+</Text>
</TouchableOpacity>
</View>
);
}
}
My Submit component looks like this. on button Submit i want to pass data from inputs to MainPage, add it to array and then display it in scroll view:
class Submit extends Component {
constructor(props) {
super(props);
this.state = {
liters: '',
time: '',
};
}
goBack() {
this.props.navigation.goBack();
this.props.navigation.state.params.addNode({
time: this.state.time,
liters: this.state.liters,
});
}
render() {
return (
<View>
<Text>Form</Text>
<TextInput
onChangeText={time => this.setState({time})}
value={this.state.time}
/>
<TextInput
onChangeText={liters => this.setState({liters})}
value={this.state.liters}
/>
<Button title="Submit" onPress={this.goBack} />
</View>
);
}
}
When i click Submit from my Submit component i get error presented in this screen:
My question is, how to pass data back to parent component from children component using StackNavigator? What im doing wrong here?

Related

Constructor of Component is not working for the second time

I have a Component class:
class AutoPage extends Component {
constructor(props) {
super(props);
console.log("Auto is " + this.props.route.params.auto);
this.state = {
avto: this.props.route.params.auto,
}
this.array = [
this.state.avto.PICTURE,
];
for (let dopImage of this.state.avto.DOP_FOTO.VALUE) {
this.array.push(dopImage);
//console.log(avto);
}
}
}
I am opening this Component from another place:
<TouchableOpacity onPress={() => navigate('AutoPage', {
auto: item
})}>
Here is my drawer navigation:
<Drawer.Navigator drawerContent={props => <CustomSidebarMenu {...props} />} width={Dimensions.get('window').width - 130}
component={CustomSidebarMenu}>
<Stack.Screen name="AutoListPage" component={AvtoListPageNav} />
<Stack.Screen name="AutoPage" component={AutoPage} options={{ headerTitle: "GorodAvtoPrime", headerTitleAlign: "center" }} />
</Drawer.Navigator>
When I click TouchableOpacity AutoPage opens and its constructor works. But when go back and click TouchableOpacity again, AutoPage opens and its constructor doesn't work. And I am getting previous data in this.props.route.params.auto. How can I make run constructor of AutoPage every time when I click TouchableOpacity?
You'll probably want to subscribe to the focus navigation event. The screen is being reused so it isn't created again.
https://reactnavigation.org/docs/navigation-events
class AutoPage extends Component {
constructor(props) {
super(props);
this.state = {
avto: null,
}
}
componentDidMount() {
this._unsubscribe = this.props.navigation.addListener('focus', () => {
// Update your state here
});
}
componentWillUnmount() {
this._unsubscribe();
}
}

passing array state to another class react native

I am new to React Native. I am making a lunch picker app for practice, and I wonder how to pass array of state to another class.
What I want to do is: show all data of array in child screen, so users can check the data by clicking on a button.
However, it seems like my code returns null array instead of getting original array. All codes are in one file, App.js
Home screen
class HomeScreen extends React.Component {
//initial
constructor(props) {
super(props);
this.state = {
isReady: false,
myMenu: '????',
menutext: '',
randomArray: ['a', 'b', 'c'],
};
}
render() {
return (
<View style={[styles.mainContainer]}>
<DetailsScreen menuListAA={this.state.randomArray} />
<Button
label="Show all menu"
onPress={() => {
/* 1. Navigate to the menu page route with params */
this.props.navigation.navigate('Details', {
itemId: 0,
otherParam: 'Show all menu',
});
}}
/>
</View>
Details screen
class DetailsScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
static navigationOptions = {
title: 'All menu',
};
loadMenuList() {
const allMenuList = this.props.menuListAA;
return allMenuList.map((item, index) => <Text key={index}>{item}</Text>);
}
render() {
return (
<ScrollView>
<View style={styles.row}>{this.props.menuListAA}</View>
<Button
label="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</ScrollView>
);
}
}
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
Let me know if you need more information.
Please replace your code with one below :
Home screen
class HomeScreen extends React.Component {
//initial
constructor(props) {
super(props);
this.state = {
isReady: false,
myMenu: '????',
menutext: '',
randomArray: ['a', 'b', 'c'],
};
}
render() {
return (
<View style={[styles.mainContainer]}>
<DetailsScreen menuListAA={this.state.randomArray} />
<Button
label="Show all menu"
onPress={() => {
/* 1. Navigate to the menu page route with params */
this.props.navigation.navigate('Details', {
itemId: 0,
otherParam: 'Show all menu',
});
}}
/>
</View>
Doubts Detail : replace View with Text component
class DetailsScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
static navigationOptions = {
title: 'All menu',
};
loadMenuList() {
const allMenuList = this.props.menuListAA;
return allMenuList.map((item, index) => <Text key={index}>{item}</Text>);
}
render() {
return (
<ScrollView>
//change View with Text as view cannot render characters and error says the same
<Text style={styles.row}>{this.props.menuListAA}</Text>
<Button
label="Go back"
onPress={() => this.props.navigation.goBack()}
/>
</ScrollView>
);
}
}
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
you can pass data from parent to child by set props for child component like this: <Child data={this.state.yourData} /> //the props name is data,
then in child component in componentWillMount() you can access it:
ComponentWillMount(){
this.setState({childData: this.props.data}) // childData is an state of child component,rename it to your own`
}
in some case data maybe changed so we must to check this in componentDidUpdate() :
componentDidUpdate(){
if(this.props.data != this.state.childData){ //it is necessary because this function called many time's
this.setState({childData: this.props.data})
}
if you was in parent & want to give any data from child you must pass a function that returned data as like below:
<Child getData={(value)=> console.log(value)} />
then in your child you can do this:
this.props.getData(anyDataYouWantGetInParent)
hope this answer will be helpful,let me know any question
good luck.

How change a state variable via props?

I'm trying do show a modal screen with a button, when i press the button the modal will appears. The variable that is responsable for it is modalVisible and its a variable state. But if my button is not in the same class of my screen Profile i'm not able to change the variable, at last i dont know a way to do:
class Carrousel extends React.Component {
render () {
return (
<Button
title= 'press me to show up'
onPress= {() => this.props.visible = true}
/>
);
}
}
export default class Profile extends React.Component {
constructor(props) {
super(props);
this.state = {
modalVisible: true,
};
}
render() {
return (
<View>
<Modal
visible = {this.state.modalVisible}>
</Modal>
<Carrousel visible = {this.state.modalVisible}/>
</View>
);
}
}
Is there an way to change this variable modalVisible in another class? Or is there another way to i show the modal with a button in another class?
*The carrousel class is another file Carrousel.js.
You have to set a function as a prop that changes the state on the Parent Component. I haven't tried but it should be something like this:
class Carrousel extends React.Component {
render () {
return (
<Button
title= 'press me to show up'
onPress= {() => this.props.setVisible()}
/>
);
}
}
export default class Profile extends React.Component {
constructor(props) {
super(props);
this.state = {
modalVisible: false,
};
this.setVisible = this.setVisible.bind(this);
}
setVisible() {
this.setState({
modalVisible: true,
})
}
render() {
return (
<View>
<Modal
visible = {this.state.modalVisible}>
</Modal>
<Carrousel setVisible={this.setVisible}/>
</View>
);
}
}

Passing React Native Input Field to State

Background
I am working with a React Native application and I have a login form. The login form input field is passing email to state on button click.
I am trying to console.log the email field. this.state.email but I keep getting email not defined.
I have removed the firebase functions to make it easier to read. But at the top of the form the console.log never succeeds.
Examples
These are the components I am working with.
Input Component
This input component is to be used in LoginForm.
class Input extends Component {
constructor(props) {
super(props);
this.state = {
value: '',
onChangeText: ''
}
}
render() {
return(
<View}>
<Text>{this.props.label}</Text>
<TextInput
value={this.value}
onChangeText={this.onChangeText}
/>
</View>
);
}
}
LoginForm Component
class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
};
}
signIn() {
console.log(this.state.email);
}
render() {
return(
<Card>
<CardSection>
<Input
value={this.state.email}
onChangeText={(email) => this.setState({email})}
/>
</CardSection>
<CardSection>
<Button
onPress={() => this.signIn()}
btnTxt='Sign In'
/>
</CardSection>
</Card>
);
}
Question
What is the proper way to pass the input field "email" to state so I can use it in my Firebase Authentication function?
In the code featured in your question, your Input component is calling this.onChangeText on onChangeText, this isn't referencing the same function you passed down as a prop from LoginForm.
class Input extends Component {
constructor(props) {
super(props);
this.state = {
value: '',
onChangeText: '',
};
}
render() {
return (
<View>
<Text>{this.props.label}</Text>
<TextInput
value={this.value}
onChangeText={email => this.props.onChangeText(email)}
/>
</View>
);
}
}

loading/importing contents of Modal from another js (class) file in react-native

My modal displays an input form. I want to import contents of my Modal from another js file for keeping the main code shorter. I am actually able to import contents of my Modal from another class file by calling component's class name as jsx tag, but in this case I cannot pass state variables of main component to inner component of the modal or vice versa. And, I don't know if it is possible to receive data from the modal in this case. I know that I could use navigator with passProps, but I want to use just a modal for this purpose. For instance:
this is main Component:
class Main extends React.Component {
constructor(props){
super(props);
this._showAddNewModal = this._showAddNewModal.bind(this);
this.state = {
addNewShow: false,
mytext: '' // this should be updated through Modal.
}
}
render(){
return (
<TouchableHighlight onPress={() => {this._showAddNewModal();}}>
<Text> Show my modal </Text>
</TouchableHighlight>
<Modal visible={this.state.addNewShow}>
<MyModalContents />
</Modal>
);
}
_showAddNewModal(){
this.setState({addNewShow: true});
}
}
this is the component to be displayed in the modal:
class MyModalContents extends React.Component { // extends Modal?
constructor(props){
super(props);
this.state = {mytext: ''}
}
render(){
<View>
<TextInput onChangeText={(text) => this.setState({mytext: text})} />
</View>
}
}
I can't even close the modal because the state of 'addNewShow' is not accessible from MyModalContents. Any help will be appreciated.
You can pass props to a child component by cloning it with React.cloneElement. Here's an example of how you could use it with your modal:
class Main extends React.Component {
constructor(props){
super(props);
this.state = {
mytext: '' // this should be updated through Modal.
}
}
_showAddNewModal(){
this.refs.modal.show();
}
render(){
return <View>
<TouchableHighlight onPress={this._showAddNewModal}>
<Text> Show my modal </Text>
</TouchableHighlight>
<Modal parent={this} ref="modal">
<MyModalContents />
</Modal>
</View>
}
}
Modal
class Modal extends React.Component {
constructor(props){
super(props);
this.state = {
visible: false,
}
}
show() {
this.setState({visible: true});
}
close(){
this.setState({visible: false});
}
render(){
return <View style={{opacity: this.state.visible ? 1 : 0}} pointerEvents={this.state.visible ? 'auto' : 'none'}>
{/* can pass props with second argument */}
{React.cloneElement(this.props.children, {
parent: this.props.parent,
modal: this
})}
</View>
}
}
MyModalContents
class MyModalContents extends React.Component {
constructor(props){
super(props);
}
_updateModalState() {
const self = this;
// will update the "Main" component state as props are passed through modal
this.props.parent.setState({myText: 'Updated Text!'}, () => {
self.props.modal.close();
});
}
render(){
return <View>
<TouchableHighlight onPress={this._updateModalState}>
<Text> Update Modal State </Text>
</TouchableHighlight>
</View>
}
}