我最近看到过这种类型的反应模式,其中使用this.state
在渲染中设置状态:
class ShowMe extends React.Component {
constructor(props) {
super(props);
this.state = {
showButton: false,
};
}
render() {
if (this.props.show) {
this.state.showButton = true; //setting state in render!!
}
return (
<div>
<div> Show or hide button </div>
{this.state.showButton && <Button content='Btn'/>}
</div>
)
}
}
这似乎是一种反模式。这会导致错误吗?它似乎工作正常。
我只想使用组件生命周期来设置状态:
class ShowMe extends React.Component {
constructor(props) {
super(props);
this.state = {
showButton: false,
};
}
componentWillReceiveProps(nextProps) {
if(nextProps.show) {
this.setState({
showButton: true,
})
}
}
render() {
return (
<div>
<div> Show or hide button </div>
{this.state.showButton && <Button content='Btn'/>}
</div>
)
}
}
推荐的方式是什么?
答案 0 :(得分:4)
render
应该始终纯,没有任何副作用,所以这肯定是一种不好的做法。
:
render()函数应该是纯的,这意味着它不会修改组件状态,每次调用时都返回相同的结果,并且它不直接与浏览器交互。如果需要与浏览器进行交互,请在componentDidMount()或其他生命周期方法中执行您的工作。保持render()纯粹使组件更容易思考。
答案 1 :(得分:3)
这是一种反模式。如果showButton状态并不总是等于show props(在示例中就是这种情况),我会使用它:
class ShowMe extends React.Component {
constructor(props) {
super(props);
this.state = {
showButton: this.props.show,
};
}
componentDidUpdate(prevProps, prevState) {
prevProps.show !== this.props.show && this.setState({showButton: this.props.show})
}
render() {
return (
<div>
<div> Show or hide button </div>
{this.state.showButton && <Button content='Btn'/>}
</div>
)
}
}
编辑:从React 16.3开始,在这种情况下应该使用 getDerivedStateFromProps 。
请注意, componentWillReceiveProps将被弃用。
从文档: getDerivedStateFromProps在实例化组件之后以及接收新道具时调用。它应该返回一个更新状态的对象,或者返回null以指示新的props不需要任何状态更新。
https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
答案 2 :(得分:1)
渲染方法中的设置状态不正确。您可以在生命周期方法中设置状态。但是其他方面是你的组件可以多次接收相同的道具,因此你的组件将被设置多次状态并进行渲染。要解决此问题,您需要将新的与当前道具进行比较,例如比较json对象:
componentWillReceiveProps(nextProps) {
if(JSON.stringify(this.props) !== JSON.stringify(nextProps) && nextProps.show) {
this.setState({
showButton: true,
})
}
}
或使用PureComponent
。并且,您可以保证您的组件不会不断重新呈现。
如果state.showButton
当前设置为true,则不会重新呈现组件会更好。
componentWillReceiveProps(nextProps) {
if(JSON.stringify(this.props) !== JSON.stringify(nextProps) && nextProps.show) {
if(!this.state.showButton) {
this.setState({
showButton: true,
})
}
}
}