如何从父类动态更改子类的状态?反应原生

时间:2018-10-06 20:12:53

标签: react-native

所以,这是父类

export default class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
        text: '',
        pickedTxtMsgType: enums.TxtMsgType.CONFIRM_PHONE_NUMBER

    }
  }

  render() {
    return (
      <View style={styles.parentView}>

        <View style={styles.view3}>
            <TxtMsgParamView
                onChangeText = {(text) => this.setState({text: text})}
                txtMsgType = {this.state.pickedTxtMsgType}
            >   
            </TxtMsgParamView>
        </View>



        <View style={styles.view4}>
            <TxtMsgTypePicker
                onValueChange = {(pickedTxtMsgType) => this.setState({pickedTxtMsgType: pickedTxtMsgType})}
            >
            </TxtMsgTypePicker>
        </View>

      </View>
    );
  }
}

当TxtMsgTypePicker类选择一个值时,它将设置 state.pickedTxtMsgType 。在整个应用程序中,此类可以选择多个值。我希望将TxtMsgTypePicker类中的选择传递给子类,并从子类中设置状态。这是子类:

export class TxtMsgParamView extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      txtMsgType: this.props.txtMsgType
    }
    this.visibilityManager = new VisibilityManager()
    this.txtMsgCreator = new TxtMsgCreator()

  }

  onChangeText(text, txtMsgParamType) {
    this.txtMsgCreator.setTxtMsgParamValue(text, txtMsgParamType)
    var txtMsg = this.txtMsgCreator.createTxtMsg(this.state.txtMsgType)
    this.props.onChangeText(this.state.txtMsgType)
  }
}

但是,问题是,在子类中,即使TxtMsgTypePicker类选择了其他值,txtMsgType仍为 enums.TxtMsgType.CONFIRM_PHONE_NUMBER 。因此,子类仅具有由TxtMsgTypePicker类设置的初始值。并且不允许T​​xtMsgTypePicker类为子类中的txtMsgType设置不同的值。

感谢您的帮助:)

1 个答案:

答案 0 :(得分:1)

您是否尝试过使用生命周期方法componentWillReceiveProps

它看起来像这样:

export class TxtMsgParamView extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      txtMsgType: this.props.txtMsgType
    }
    this.visibilityManager = new VisibilityManager()
    this.txtMsgCreator = new TxtMsgCreator()

  }

  componentWillReceiveProps(nextProps) {
    if (this.props.txtMsgType !== nextProps.txtMsgType) {
      this.setState({txtMsgType: nextProps.txtMsgType})
    }
  }

  onChangeText(text, txtMsgParamType) {
    this.txtMsgCreator.setTxtMsgParamValue(text, txtMsgParamType)
    var txtMsg = this.txtMsgCreator.createTxtMsg(this.state.txtMsgType)
    this.props.onChangeText(this.state.txtMsgType)
  }
}

尽管componentWillReceiveProps在最新的React中被视为UNSAFE,但事实证明在这种情况下它很有用。同样,如果您的组件找不到componentWillReceiveProps,请尝试UNSAFE_componentWillReceiveProps。如果您想了解更多信息,请前往:https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops

编辑:上面的答案有充分的理由被认为是不安全的。它导致反模式,尽管可以避免,但经常会偶然发生。

getDerivedStateFromProps(道具,状态)

随着componentWillReceiveProps的缓慢淘汰,React团队引入了getDerivedStateFromProps,它以一种更安全的方式执行componentWillReceiveProps的工作。

在此生命周期方法中,您应该返回一个对象,该对象包含您要根据道具修改的状态字段;如果新的道具不需要更改状态,则返回null。 / p>

以用例为例,您将需要更改:

  componentWillReceiveProps(nextProps) {
    if (this.props.txtMsgType !== nextProps.txtMsgType) {
      this.setState({txtMsgType: nextProps.txtMsgType})
    }
  }

收件人:

  getDerivedStateFromProps(props, state) {
    if (props.txtMsgType !== state.txtMsgType) {
      return ({txtMsgType: props.txtMsgType})
    }
  }

但是,即使是this approach has its drawbacks.

真理的唯一来源

在您的示例用法中,安装TxtMsgParamView时,父级(App)为它提供将要显示的数据。这是true数据。但是,一旦安装了组件并且用户对TxtMsgParamView进行了更改,则是子级(TxtMsgParamView)将数据保持其状态,因此source of truth从父级更改了给孩子。父母可以超越孩子的state但始终不知道stateleads to bugs是什么的事实。

因此,您应该高度考虑将数据移至单个事实来源。如上一篇文章的使用派生状态时的常见错误部分所述,“受控”和“不受控制”的含义如下:

  

“受控”和“不受控制”一词通常是指表单输入,但它们也可以描述任何组件的数据在何处。可以将作为道具传递的数据视为受控的(因为父组件控制着该数据)。只能将内部状态的数据视为不受控制的数据(因为父级无法直接对其进行更改)。

我认为最好的想法是选择最适合您需求的一个,并坚持下去。

受控组件

以您的示例为例,由于TxtMsgTypePicker的兄弟姐妹TxtMsgParamView可以修改父级的state,因此也可以修改TxtMsgParamView的{​​{1}},我建议使用受控组件。

这意味着state将完全控制App呈现的内容,从而使TxtMsgParamView成为无状态组件:

App.js

TxtMsgParamView

TxtMsgParamView.js

export default class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
        text: '',
        pickedTxtMsgType: enums.TxtMsgType.CONFIRM_PHONE_NUMBER
    }
  }

    this.onTxtMsgChange = (text, txtMsgParamType) => {
        this.txtMsgCreator.setTxtMsgParamValue(text, txtMsgParamType)
        var txtMsg = this.txtMsgCreator.createTxtMsg(this.state.txtMsgType)
        this.setState({pickedTxtMsgType: txtMsg})
    }

  render() {
    return (
      <View style={styles.parentView}>

        <View style={styles.view3}>
            <TxtMsgParamView
                onChangeText = {this.onTxtMsgChange}
                txtMsgType = {this.state.pickedTxtMsgType}
            >   
            </TxtMsgParamView>
        </View>



        <View style={styles.view4}>
            <TxtMsgTypePicker
                onValueChange = {(pickedTxtMsgType) => this.setState({pickedTxtMsgType: pickedTxtMsgType})}
            >
            </TxtMsgTypePicker>
        </View>

      </View>
    );
  }
}

虽然我不知道您的用例的全部代码,但在我的示例代码中要注意的重要一点是export class TxtMsgParamView extends React.Component { onChangeText(text, txtMsgParamType) { this.props.onChangeText(text, txtMsgParamType) } render() { const {txtMsgParamType} = this.props return <TextInput value={txtMsgParamType} onChangeText={this.onChangeText} /> } } 没有状态,并且让父TxtMsgParamView处理更改文字。本质上,App.js是一个愚蠢的组件,仅将其作为props发送的数据进行渲染,并在需要时调用父级发送的函数。它本身不会以任何方式修改数据。

像这样,onTxtMsgChange现在是事实的唯一来源,并且您已经节省了一些调试时间来查找App上的错误。