Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing state from parent to child component in React

I am having an issue binding the state of a parent component to the state of a child. A look at the code:

Parent Component:

    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>
        );
    }

Child Component:

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>
    );
  }
}

In the Parent Component, if I make the state.showDialog property true, the dialog will open when the page loads. But once I close it one time, I am never able to open it again. If I have it set to false, it doesn't load when the page loads, and I am never able to open the dialog, even when I click the button on the parent component. Thank you in advance for taking your time to help.

like image 597
Shawn Avatar asked Jun 21 '17 05:06

Shawn


2 Answers

Since you are setting the local state based on the parent, you need to make use of componentWillReceiveProps before v16.3.0 or getDerivedStateFromProps/memoization/key modification thereafter, since your state is set only on the first time and never thereafter. However you don't even need a local state in MyDialog component, you can just make use of Props and communicate from child to the parent component.

Parent

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 (child)

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>
    );
  }
}
like image 178
Shubham Khatri Avatar answered Sep 22 '22 17:09

Shubham Khatri


handleRequestClose method should be like this.

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

Edit 1.

You also need to update the parent state when you close the dialog.

    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>
        );

And,

 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);
        });

      };
like image 21
Ved Avatar answered Sep 22 '22 17:09

Ved