免责声明:我看过Reactjs: how to modify child state or props from parent?并且不相信答案符合我的问题。
所以我有一个可重用的、有状态的对话组件,它根据其状态呈现不同的 DOM。我还必须能够控制从父级渲染哪个 DOM。
TL;DR - 我应该如何从父组件改变子组件的状态,如果有的话,还有哪些其他选项?
child :
export default class Conversation extends Component {
constructor(props) {
super(props);
this.state = {
newConversation: props.showNewConversation
};
}
render() {
if (!this.state.newConversation) {
return (
<div>Current Conversation</div>
);
} return (
<div>New Conversation</div>
);
}
}
现在我需要在不同的地方渲染这个组件,但是我需要根据父组件渲染适当的 DOM,即从导航栏你可以创建一个新的对话,从用户页面你可以直接进入你的对话和他们在一起,这样我就可以控制何时通过它的 Prop 调用 child 。
通过 prop 调用子进程并设置状态:
<Conversation
showNewConversation={this.state.isConversationShown === true}
/>
这目前正在工作,但我被告知这是 React 中的一个非常糟糕的实践,我的问题实际上是为什么这被认为是不好的实践,以及一个好的实践解决方案是什么样的。
最佳答案
在 React 中,一般的最佳实践是如果可能的话,使尽可能多的组件“无状态”。通常,如果您不加载异步数据或接受用户输入,则不需要状态。
在此示例中,主要问题如下:如果父渲染
<Conversation newConversation={true} />
稍后将其重新渲染为
<Conversation newConversation={false} />
然后子级将不会按预期渲染,因为 React 将“更新”子级对话(重新渲染),但不会再次调用构造函数。因为您只将 props 转移到构造函数中的状态,所以子级永远不会改变。
大多数组件应该仅根据其属性进行渲染。您的 child 可以适应以下情况:
export default class Conversation extends Component {
constructor(props) {
super(props);
}
render() {
if (!this.props.newConversation) {
return (
<div>Current Conversation</div>
);
} return (
<div>New Conversation</div>
);
}
}
在这里,父级的更新将允许子级正确地重新渲染,因为您直接引用子级的 render() 函数中的 props。
如果您有更多有关正在呈现的对话的数据,那么您应该将所有数据作为 Prop 传递。即
<Conversation conversationData={{name: 'abc', new: false}} />
然后Conversation组件就可以直接在render()方法中访问props了。
如果您绝对必须更改状态,那么它应该采用父级更改 props 的形式:
export default class Conversation extends Component {
constructor(props) {
super(props);
this.state = {
newConversation: props.showNewConversation
};
}
// Response to change
componentWillReceiveProps(nextProps){
this.setState({newConversation: this.props.showNewConversation});
}
render() {
if (!this.state.newConversation) {
return (
<div>Current Conversation</div>
);
} return (
<div>New Conversation</div>
);
}
}
关于javascript - ReactJS:通过 props 从父级改变子级状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38135445/