【问题标题】:Sharing state from parent to child component in React在 React 中从父组件到子组件共享状态
【发布时间】:2017-11-23 20:43:25
【问题描述】:

我在将父组件的状态绑定到子组件的状态时遇到问题。看一下代码:

父组件:

    class ParentForm extends React.Component {
        constructor(){
            super();
            this.state = {
                showDialog: false
            };
        }

        toggleDialog() {
            this.setState({showDialog: !this.state.showDialog});
        }

        return (
                <div >
                    <Button color='primary' onClick={() => this.toggleDialog()}></Button>
                    <MyDialog open={this.state.showDialog}/>
                </div>
        );
    }

子组件:

export default class MyDialog extends Component {
    constructor(props){
        super(props);
        this.state = {
            open: this.props.open
        };
    }

  handleRequestClose = () => {
    this.setState({ open: false });
  };

  render() {
    return (
      <div>
        <Dialog
          fullScreen
          open={this.state.open}
          onRequestClose={() => this.handleRequestClose()}
          transition={<Slide direction="up" />}
        >
         <DialogTitle>{'Title'}</DialogTitle>
          <DialogContent>
            <DialogContentText>
              This is my dialog
            </DialogContentText>
          </DialogContent>
          <DialogActions>
            <Button onClick={() => this.handleRequestClose()} color="primary">Close</Button>
          </DialogActions>
        </Dialog>
      </div>
    );
  }
}

在父组件中,如果我将 state.showDialog 属性设置为 true,则该对话框将在页面加载时打开。但是一旦我关闭它一次,我就再也无法打开它了。如果我将其设置为 false,则在页面加载时它不会加载,并且我永远无法打开对话框,即使我单击父组件上的按钮也是如此。提前感谢您抽出宝贵时间提供帮助。

【问题讨论】:

  • 您不应该将组件的状态值设置为属性值。关键是,如果您从父级更改属性,则会触发重新渲染,并且此新值将传递给子级并成为this.props.whatever 的新值。所以在孩子身上,你应该使用this.props.open

标签: javascript reactjs react-redux material-ui


【解决方案1】:

由于您是根据父级设置本地状态,因此您需要在 v16.3.0 之前使用componentWillReceiveProps 或之后使用getDerivedStateFromProps/memoization/key modification,因为您的状态仅设置在第一个时间,以后再也不。但是,您甚至不需要 MyDialog 组件中的本地状态,您可以使用 Props 并从子组件与父组件进行通信。

家长

class ParentForm extends React.Component {
        constructor(){
            super();
            this.state = {
                showDialog: false
            };
        }

        toggleDialog() {
            this.setState({showDialog: !this.state.showDialog});
        }
        closeDialog() {
           this.setState({showDialog: false})
        }
        return (
                <div >
                    <Button color='primary' onClick={ this.toggleDialog}></Button>
                    <MyDialog open={this.state.showDialog} closeDialog={this.closeDialog}/>
                </div>
        );
    }

MyDialog(子)

export default class MyDialog extends Component {
  constructor(props){
    super(props);    
  }

  render() {
    return (
      <div>
        <Dialog fullScreen open={this.props.open} onRequestClose={this.props.closeDialog} transition={<Slide direction="up" />}>
         <DialogTitle>{'Title'}</DialogTitle>
          <DialogContent>
            <DialogContentText>
              This is my dialog
            </DialogContentText>
          </DialogContent>
          <DialogActions>
            <Button onClick={this.props.closeDialog} color="primary">Close</Button>
          </DialogActions>
        </Dialog>
      </div>
    );
  }
}

【讨论】:

  • 顺便说一句,更新状态时最好是this.setState((prevState) =&gt; ({showDialog: !prevState.showDialog}));
  • 这根本不共享状态,因为状态必须只能通过setState 修改,如第一条评论所述。
【解决方案2】:

handleRequestClose 方法应该是这样的。

 handleRequestClose = () => {
        this.setState({ open: this.props.open});
      };

编辑 1。

您还需要在关闭对话框时更新父状态。

    toggleDialog(val) {
     if(val){
       this.setState({showDialog: val});
       }else {
     this.setState({showDialog: !this.state.showDialog});
       }
    }

 return (
          <div >
            <Button color='primary' onClick={() => this.toggleDialog()}></Button>
            <MyDialog toggleDialog = {this.toggleDialog} open={this.state.showDialog}/>
          </div>
        );

还有,

 componentWillRecieveProps(nextProps) {//Lifecycle method to get the updated props
    this.setState({ open: nextProps.open });
}

handleRequestClose = () => {
        this.setState({ open: !this.state.open},()=>{
              this.props.toggleDialog (this.state.open);
        });

      };

【讨论】:

  • 我试过那个。问题似乎是打开对话框,因为我无法显示它,所以我永远无法关闭对话框来触发子组件上的 handleRequestClose 方法
  • React 文档说componentWillRecieveProps 将很快被弃用。
【解决方案3】:

您的子组件目前只接收父组件的 showDialog 属性值一次,仅当它在构造函数中启动时。

您需要使用 componentWillRecieveProps 和子组件的 setState 来更新值。

所以:

componentWillRecieveProps(nextProps) { this.setState({ open: nextProps.open }); }

编辑:需要使用 nextProps,而不是 this.props

class ParentForm extends React.Component {
        constructor(){
            super();
            this.state = {
                showDialog: false
            };
        }

        toggleDialog() {
            this.setState({showDialog: !this.state.showDialog});
        }

         closeDialog() {
            this.setState({showDialog: false});
        }

        return (
                <div >
                    <Button color='primary' onClick={() => this.toggleDialog()}></Button>
                    <MyDialog open={this.state.showDialog} closeDialog={() => this.closeDialog()/>
                </div>
        );
}

export default class MyDialog extends Component {
    handleRequestClose = () => {
        this.props.closeDialog();
    };

    render() {
        return (
            <div>
                <Dialog
                    fullScreen
                    open={this.state.open}
                    onRequestClose={() => this.handleRequestClose()}
                    transition={<Slide direction="up" />}
                >
                    <DialogTitle>{'Title'}</DialogTitle>
                    <DialogContent>
                        <DialogContentText>
                            This is my dialog
                        </DialogContentText>
                    </DialogContent>
                    <DialogActions>
                        <Button onClick={() => this.handleRequestClose()} color="primary">Close</Button>
                    </DialogActions>
                </Dialog>
            </div>
        );
    }
}

【讨论】:

  • 应该 componentWillRecieveProps 是子 MyDialog 类的一部分吗?
  • @MiFreidgeimSO-stopbeingevil 是的?
猜你喜欢
  • 2019-02-12
  • 2016-01-25
  • 1970-01-01
  • 2020-08-07
  • 2017-12-06
  • 1970-01-01
  • 2023-01-19
  • 2019-01-31
  • 1970-01-01
相关资源
最近更新 更多