web-dev-qa-db-fra.com

Réagissez natif comment passer le changement this.setState au parent

Je suis nouveau à React Native Je crée un exemple d'application où l'utilisateur peut se connecter et s'inscrire pour un nouveau compte. 

J'ai deux cours de React, 

L'une est la classe principale index.ios.js et une autre classe appelée register.js. Dans la classe d'index, je dis que si la variable register est vraie, restituer l'écran du registre. 

Dans la classe register.js, j'essaie de définir le registre de variable sur false à l'aide de this.setState ({register: false}), mais ne provoque pas le rendu du parent (index.ios.js). La méthode super (state) ou quelque chose de similaire me manque-t-elle? Je crois que l'état parent n'obtient pas les valeurs de la variable de registre mise à jour. 

Voici mes cours: 

Render dans 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;

Tentative 1

Selon la réponse, j'ai ajouté ceci à mon index.ios.js

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

Et j'ai ajouté ceci à mon register.js

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

Mais pour une raison quelconque, il n’a même plus accès à l’écran d’enregistrement, il exécute la fonction d’identification dès que l’écran d’enregistrement est rendu. Qu'est-ce qui me manque maintenant? S'il vous plaît donnez votre avis. 

Merci

Mettre à jour

Cela fonctionne quand je passe enregistré comme une propriété mais pas quand je ne le fais pas. J'aimerais comprendre pourquoi si quelqu'un pouvait poster ça. 

Merci

21
alyn000r

Vous pouvez transmettre la fonction à l'enfant sous forme d'accessoires, puis définir ainsi l'état du parent depuis l'enfant. 

Composant parent:

   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>
    );
  }
});

Composant enfant:

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>
    ) 
  }
})
27
Nader Dabit

Voici une solution plus puissante. Cela laissera le composant enfant modifier n'importe quelle variable d'état dans le parent. 

Composant parent:

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

// Prendre note de la setState ()

Composant enfant:

this.props.setParentState({registered: true})
16
Shuming Chan

Pourquoi ma tentative a échoué était parce que j'utilisais

onPress={this.props.login}

CA devrait etre 

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

à cause de cette erreur, ma fonction onPress s'exécutait dès que le bouton était rendu. Je ne sais pas pourquoi cela se produit mais je sais quelle était mon erreur. 

2
alyn000r

En utilisant StackNavigator, j'ai trouvé une âme exploitant screenProps. Ici, vous pouvez transmettre des fonctions et des valeurs à vos itinéraires. L'état global de l'application est géré dans App. App passe ensuite dans les fonctions et/ou l'état à NavComponentscreenProps. Chaque route enfant dans StackNavigator aura alors accès via this.props.screenProps

Cette solution fonctionne bien pour l'instant. J'aimerais des commentaires ou des suggestions pour améliorer cette méthode

class HomeScreen extends React.Component {

  render() {
    return (
      <View>
        <Text>{JSON.stringify(this.props.screenProps.awesome)}</Text>
        <Button
          onPress={() => this.props.screenProps.updateGlobalState("data")}
          title="Update parent State"
        />
      </View>
    );
  }
}

const NavComponent = StackNavigator({
  Home: { screen: HomeScreen },
  // AllOthers: { screen: AllComponentsHereMayAccessScreenProps },
});

export default class App extends React.Component {
  constructor() {
    super();
    this.state = {
      everythingIsAwesome: false,
    }
  }

  _updateGlobalState(payload) {
    console.log('updating global state: ', payload);
    this.setState({everythingIsAwesome: payload});
  }

  render() {
    return <NavComponent screenProps={{
      updateGlobalState: this._updateGlobalState.bind(this),
      awesome: this.state.everythingIsAwesome
    }} />;
  }
}
0
Vinnie James