Elder
Elder

Reputation: 363

Update state when props change

I have a problem with update props.


I have two components.

The first is the App, where there is a button that opens or closes the modal.

The second is the modal structure.
The first component stores the state, I click the buton, the state changes, I send props to ModalComponent component (the modal is opening).
And in this component should change this state if I want to close modal.
But if I click on the Cancel button in modal, nothing happens.
The state does not change.

How to change it, how it would make communication between the child and the parent?

This is my code : ModalComponent

import React, { Component } from "react";
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";

class ModalComponent extends Component {
  constructor(props) {
    super(props);

    this.state = {
      modal: props.modal
    };

    this.toggle = this.toggle.bind(this);
  }

  toggle() {
    const { modal } = this.state;
    this.setState({
      modal: !modal
    });
  }

  render() {
    const { modal } = this.props;
    return (
      <div>
        <Modal isOpen={modal} toggle={this.toggle}>
          <ModalHeader toggle={this.toggle}>Halo</ModalHeader>
          <ModalFooter>
            <Button onClick={this.toggle}>Cancel</Button>
          </ModalFooter>
        </Modal>
      </div>
    );
  }
}

export default ModalComponent;

App

import React from "react";
import ReactDOM from "react-dom";
import Modal from "./modal";
import { Button } from "reactstrap";

import "./styles.css";

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      modal: false
    };
    this.toggle = this.toggle.bind(this);
  }

  toggle() {
    const { modal } = this.state;
    this.setState({
      modal: !modal
    });
  }

  render() {
    const { modal } = this.state;
    return (
      <div>
        <Button
          type="link"
          onClick={this.toggle}
        >
          Delete account
        </Button>
        <Modal modal={modal} />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Upvotes: 0

Views: 2145

Answers (2)

Shubham Khatri
Shubham Khatri

Reputation: 282030

The state in your Modal Component would change but you aren't using it to set the isOpen props on Modal component.

Also you must not use state which is directly derivable from props. You must instead pass a handler from Parent to update the state in the parent itself

ModalComponent

import React, { Component } from "react";
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";

class ModalComponent extends Component {
  render() {
    const { modal } = this.props;
    return (
      <div>
        <Modal isOpen={modal} toggle={this.toggle}>
          <ModalHeader toggle={this.props.toggle}>Halo</ModalHeader>
          <ModalFooter>
            <Button onClick={this.props.toggle}>Cancel</Button>
          </ModalFooter>
        </Modal>
      </div>
    );
  }
}

export default ModalComponent;

App

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      modal: false
    };
    this.toggle = this.toggle.bind(this);
  }

  toggle() {
    const { modal } = this.state;
    this.setState({
      modal: !modal
    });
  }

  render() {
    const { modal } = this.state;
    return (
      <div>
        <Button
          type="link"
          onClick={this.toggle}
        >
          Delete account
        </Button>
        <Modal modal={modal} toggle={this.toggle}/>
      </div>
    );
  }
}

Upvotes: 2

Colin Ricardo
Colin Ricardo

Reputation: 17269

The way you have it now, the modal is setting its own state, but it is still receiving a prop from the parent, which is keeping it open.

Here's an example of one way to do it. Note that both opening and closing is dealt with using the state of the parent, not the state of the child.

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends React.Component {
  state = { open: false };

  toggle = () => {
    this.setState({ open: !this.state.open });
  };

  render() {
    return (
      <React.Fragment>
        something
        <Modal show={this.state.open} />
        <Child toggle={this.toggle} />
      </React.Fragment>
    );
  }
}

const Child = ({ toggle }) => {
  return <button onClick={toggle}>toggle</button>;
};

const Modal = ({ show }) => {
  if (show) {
    return <h1>I am a modal</h1>;
  }

  return null;
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

CodeSandbox here.

Upvotes: 0

Related Questions