Javascript React Native 如何将 this.setState 更改传递给父级

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33720405/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 15:23:22  来源:igfitidea点击:

React Native how to pass this.setState change to parent

javascriptreact-native

提问by alyn000r

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

我是 React Native 的新手我正在制作一个示例应用程序,用户可以在其中登录并注册一个新帐户。

I have two React classes,

我有两个 React 类,

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.

一个是主类 index.ios.js 和另一个名为 register.js 的类。在索引类中,我说变量 register 是否为 true 渲染寄存器屏幕。

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.

在 register.js 类中,我尝试使用 this.setState({register:false}) 将变量 register 设置为 false,但它不会导致父级 (index.ios.js) 重新呈现。是超级(状态)方法还是我缺少的类似方法?我相信父状态没有获得更新的寄存器变量的值。

Here are my classes:

这是我的课程:

Render inside 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:

注册.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

尝试 1

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

根据答案,我将此添加到我的 index.ios.js

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

And I added this to my register.js

我将它添加到我的 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

谢谢

回答by Nader Dabit

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

回答by Shuming Chan

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()

// 注意 setState()

Child component:

子组件:

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

回答by alyn000r

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.

由于这个错误,我的 onPress 函数会在按钮呈现时立即执行。我不确定为什么会发生这种情况,但我知道我的错误是什么。

回答by Vinnie James

Using StackNavigatorI found a soultion leveraging screenProps. Here you can pass down functions and values to your routes. App global state is managed in App. Appthen passes in functions and/or state to NavComponentscreenProps. Each child route in StackNavigatorwill then have access via this.props.screenProps

使用StackNavigator我发现了一个利用screenProps. 在这里,您可以将函数和值传递给您的路由。应用程序全局状态在App. App然后将函数和/或状态传递给NavComponentscreenProps. StackNavigator然后,每个子路由都可以通过this.props.screenProps

This solution is working well for now. Would love some feedback, or suggestions for improving this method

该解决方案目前运行良好。希望得到一些反馈或改进此方法的建议

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