Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native how to pass this.setState change to parent

I am new to React Native I am making a sample app where the user can login and register for a new account.

I have two React classes,

One is the main class index.ios.js and another class called register.js. In the index class I am saying if the variable register is true render the register screen.

In the class register.js I am trying to set the variable register to false using this.setState({register:false}) but it is not causing the re render of the parent (index.ios.js). Is the a super(state) method or something similar that I am missing ? I believe the parent state is not getting the values of the updated register variable.

Here are my classes:

Render inside index.ios.js:

render: function() {
    if(this.state.register) {
      return this.renderRegisterScreen();
    }
    else if (this.state.loggedIn) {
      return this.userLoggedIn();
    }
    else {
      return this.renderLoginScreen();
    }
  }

Register.js:

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Image,
  TouchableHighlight,
  TextInput,
} = React;

var Register = React.createClass({
        render: function() {
        return (
          <View style={styles.container}>
            <View style={styles.rafitoImage}>
              <Image source={require('./logo.png')}></Image>
              <Text style={styles.slogan}>Eliminate the need to wait!</Text>
            </View>
            <View style={styles.bottomSection}>
              <View style={styles.username}>
                <View style={styles.inputBorder}>
                  <TextInput placeholder="Username..." style={styles.usernameInput} onChangeText={(text) => this.setState({username: text})}/>
                </View>
                <View style={styles.inputBorder}>
                  <TextInput password={true} placeholder="Password..." style={styles.usernameInput} onChangeText={(text) => this.setState({password: text})}/>
                </View>
                <View style={styles.inputBorder}>
                  <TextInput password={true} placeholder="Verify Password..." style={styles.usernameInput} onChangeText={(text) => this.setState({verifyPassword: text})}/>
                </View>
                <View style={styles.inputBorder}>
                  <TextInput placeholder="Phone.." style={styles.usernameInput} onChangeText={(text) => this.setState({phone: text})}/>
                </View>
                <View style={styles.inputBorder}>
                  <TextInput placeholder="Email.." style={styles.usernameInput} onChangeText={(text) => this.setState({email: text})}/>
                </View>
                <TouchableHighlight style={styles.button}
                  underlayColor='#f1c40f' onPress={this.register}>
                        <Text style={styles.buttonText}>Register</Text>
                </TouchableHighlight>
                <TouchableHighlight style={styles.signUp} onPress={this.resetToLogin}
                underlayColor='#ffffff'>
                <Text style={styles.signUpText}>Already A Member </Text>
                </TouchableHighlight>
              </View>
            </View>
            <View style={styles.copyright}>
            </View>
          </View>
        );
    },

    resetToLogin: function() {
        this.setState({
            register: false //I want this to re render the home screen with the variable register as false
        });
    }
});

    var styles = StyleSheet.create({
      container: {
        flex : 1
      },
      bottomSection: {
        flex: 5,
        flexDirection: 'row' 
      },
      button: {
            height: 36,
            backgroundColor: '#32c5d2',
            justifyContent: 'center',
            marginTop: 20
        },
      buttonText: {
            fontSize: 18,
            color: 'white',
            alignSelf: 'center'
      },
      signUpText: {
        color: '#3598dc'
      },
      signUp: {
        alignItems: 'flex-end',
        marginTop: 10,
      },
      username: {
        flex: 1,
        padding: 5
      },
      rafitoImage: {
        flex: 3,
        justifyContent: 'center',
        alignItems: 'center',
      },
      copyright: {
        alignItems: 'center'
      },
      usernameInput: {
            height: 36,
            marginTop: 10,
            marginBottom: 10,
            fontSize: 18,
            padding: 5
      },
      copyrightText: {
        color: '#cccccc',
        fontSize: 12
      },
      inputBorder: {
        borderBottomWidth: 1,
        borderBottomColor: '#ececec'
      },
      slogan: {
        color: '#3598dc'
      }
    });

module.exports = Register;

Attempt 1

As per the answer I added this to my index.ios.js

renderRegisterScreen: function() {
    return (
      <Register login={this.login}/>
    )
  }

And I added this to my register.js

<TouchableHighlight style={styles.signUp} onPress={this.props.login}
                underlayColor='#ffffff'>
                <Text style={styles.signUpText}>Already A Member </Text>
                </TouchableHighlight>

But for some reason it does not even go to the register screen anymore, it executes the login function as soon as the register screen renders. What am I missing now ? Please advise.

Thanks

Update

It works when I pass down registered as a property but not when I do not. I would like to understand why if someone could post that.

Thanks

like image 417
alyn000r Avatar asked Nov 15 '15 13:11

alyn000r


3 Answers

You can pass the function down to the child as props, then set the state of the parent from within the child that way.

Parent Component:

   var Parent = React.createClass({      getInitialState() {         return {             registered: false         }     },    register(){     console.log("logging in... ");     this.setState({         registered: true     });    },    render: function() {     return (       <View style={styles.container}>         <Child register={this.register.bind(this)} registered={this.state.registered} />       {this.state.registered && <View style={{padding:10, backgroundColor:'white', marginTop:10}}>                                     <Text style={{fontSize:20}}>Congratulations, you are now registered!</Text>                               </View>}        </View>     );   } }); 

Child Component:

var Child = React.createClass({  render: function() { return(     <View style={{backgroundColor: 'red', paddingBottom:20, paddingTop:20 }}>         <TouchableHighlight style={{padding:20, color: 'white', backgroundColor: 'black'}} onPress={() => this.props.register() }>  {this.props.registered ? <Text style={{color: 'white'}}>registered</Text> : <Text style={{color: 'white'}}>register</Text>}         </TouchableHighlight>                          </View>     )    } }) 
like image 139
Nader Dabit Avatar answered Sep 22 '22 04:09

Nader Dabit


Here is a more powerful solution. This will let the child component change any state variable in the parent.

Parent component:

render: function() {     return (        ...         <Child setParentState={newState=>this.setState(newState)} />        ...     ); } 

// Take note of the setState()

Child component:

this.props.setParentState({registered: true}) 
like image 22
Shuming Chan Avatar answered Sep 23 '22 04:09

Shuming Chan


Why my attempt was failing was because I was using

onPress={this.props.login}

It should be

onPress={()=>this.props.login}

because of that mistake my onPress function would execute as soon as the button would render. I am not sure why that happens but I know what my mistake was.

like image 27
alyn000r Avatar answered Sep 26 '22 04:09

alyn000r