所以,这是父类:
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类设置的初始值。并且不允许TxtMsgTypePicker类为子类中的txtMsgType设置不同的值。
感谢您的帮助:)
答案 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
编辑:上面的答案有充分的理由被认为是不安全的。它导致反模式,尽管可以避免,但经常会偶然发生。
随着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
但始终不知道state
是leads 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
上的错误。