2015-11-15 2 views
17

Я новичок в React Native Я делаю пример приложения, в котором пользователь может войти и зарегистрироваться для новой учетной записи.React Native как передать this.setState изменение родителя

У меня есть два Реагировать классов,

Одним из них является основным index.ios.js класса и другой класс называется register.js. В классе индекса я говорю, что если регистр переменной является истинным, отобразите экран регистра.

В классе register.js Я пытаюсь установить регистр переменной в false с помощью this.setState ({register: false}), но это не вызывает re-рендеринг родителя (index.ios.js). Является ли метод супер (состояние) или что-то подобное, что мне не хватает? Я считаю, что родительское состояние не получает значения обновленной переменной регистра.

Вот мои классы:

Рендер внутри 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; 

ПОПЫТКА 1

согласно ответ Я добавил это в свой index.ios.js

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

И я добавил это в моих register.js

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

Но по какой-то причине он не может даже идти на экран регистра больше, он выполняет функцию входа в систему, как только экран регистра делает , Что мне сейчас не хватает? Пожалуйста, порекомендуйте.

Благодаря

Update

Он работает, когда я прохожу вниз зарегистрирован как собственность, но не тогда, когда у меня нет. Я хотел бы понять, почему, если кто-то может это опубликовать.

Благодаря

ответ

24

Вы можете передать функцию вниз к ребенку в качестве реквизита, а затем установить состояние родителя внутри этого пути ребенка.

Родитель Компонент:

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

Детский компонент:

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> 
    ) 
    } 
}) 
+2

при передаче 'register = {this.register}' dont вам нужно привязать регистр к родительскому объекту? 'register = {this.register.bind (this)}' – Macmee

+1

@Macmee Не в этом случае, поскольку мы передаем его только как опору, а не вызываем действительную функцию. –

+0

@NaderDabit, если я пытаюсь использовать ваш код без зарегистрированной переменной, он никогда не переходит на экран регистра. Нужна ли мне зарегистрированная переменная? Я пытался сделать и внутри register.js Я пытался сделать Уже участник , но по какой-то причине он устанавливает регистр: false при загрузке экрана – alyn000r

2

Почему моя попытка терпела неудачу, потому что я использовал

onPress={this.props.login} 

Это должно быть

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

из-за этой ошибки моя функция onPress будет выполняться, как только кнопка будет отображать. Я не знаю, почему это происходит, но я знаю, какова была моя ошибка.

+3

Я думаю 'onPress = {this.props.login.bind (this)}' также может работать. –

12

Вот более мощное решение. Это позволит дочернему компоненту изменить любую переменную состояния в родительском элементе.

Родитель компонент:

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

// Обратите внимание на SetState()

Детский компонент:

this.props.setParentState({registered: true}) 
+1

Это должен быть лучший ответ – ProteanDev

+0

Согласен. Принятый ответ вызовет так много раздувания в главном App.js для любого приложения среднего размера + – webdevinci

0

Использование StackNavigator Я нашел soultion Усиливая screenProps. Здесь вы можете передать функции и значения вашим маршрутам. Глобальное состояние приложения управляется в App. App затем переходит в функции и/или в состояние NavComponentscreenProps. Каждый детский маршрут в StackNavigator будет иметь доступ через this.props.screenProps

Это решение работает хорошо. Хотелось бы получить некоторые отзывы или предложения по улучшению этого метода.

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 
    }} />; 
    } 
} 
Смежные вопросы