使用 this.state 在渲染中设置状态

Setting state in render by using this.state

我最近看到这种类型的反应模式,其中使用 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>
        )
    }
}

推荐的方式是什么?

render 应该始终是 纯的 ,没有任何 副作用 ,因此这肯定是一种不好的做法。

来自 React 文档:

The render() function should be pure, meaning that it does not modify component state, it returns the same result each time it’s invoked, and it does not directly interact with the browser. If you need to interact with the browser, perform your work in componentDidMount() or the other lifecycle methods instead. Keeping render() pure makes components easier to think about.

也看看 and

渲染方法中设置状态不正确。您可以在生命周期方法中设置状态。但另一件事是您的组件可以多次接收相同的道具,因此您的组件将多次设置状态并渲染。要解决此问题,您需要将新道具与当前道具进行比较,例如比较 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,         
        })
       }

    }
 }

这是一个反模式。如果 showButton state 并不总是等于 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 在实例化组件后以及接收新道具时调用。它应该 return 一个更新状态的对象,或者 null 表示新道具不需要任何状态更新。

https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops