0
votes

I have problem with forwarding state from parent to child component, these 2 components are class components. When forwarding state from parent to child component, I want to use state showModal variable in child component as show as state variable:

 this.state = {
     show: this.props.show
 }

This variable is being used to active the modal. When I use it as this.props.show, the state has been forwarded to child component, and updated, but when I use props in this.state in child component it hasn't been updated. Has anyone idea where the problem is?

First - Parent component:

    import React, { Component } from 'react';
    import Modal from './UI/Modal';

    class EnteredBooks extends Component {
        constructor(props) {
            super(props)

            this.state = {
                enteredBook: this.props.enteredBook,
                showModal: false
            }
        }

        detailsHandler = () => {
            this.setState({
                showModal: true
            })
        }

        render() {
            let show =  this.state.showModal;
            return (
                <div>
                     <div className="product">
                         <img src="{this.props.enteredWatch.bookUrl}" />
                         <p>{this.props.enteredWatch.bookType}</p>
                         <p>euro{this.props.enteredWatch.bookPrice}</p>
                         <button 
                             className="details-button"
                             onClick={this.detailsHandler}
                                >
                                    Details
                         </button>
                         <Modal show={this.state.showModal} watch={this.state.enteredWatch} />
                         <button className="buy-button">Buy</button>
                      </div>
                </div>
            );
        }
    }

export default EnteredWatches;

Second - Child component:

import React, {Component} from 'react';
import classes from './Modal.css';

class Modal extends React.Component {
constructor(props) {
    super(props)

        this.state = {
            book: this.props.book,
            show: this.props.show
        }
    }
return(
        <div>
             <div className="Modal"
                    style={{
                        transform: this.state.show ? 'translateY(0)' : 'translateY(-100vh)',
                        opacity: this.state.show ? '1':'0'
                    }}>

                    <img src={this.state.book.bookUrl} />
                    <p>{this.state.book.bookType}</p>
                    <p>{this.state.book.watchUrl}</p>
                    <button className="details-button">Details</button>
                    <button className="buy-button">Buy</b
                </div>
            </div>
        );
    }
}


export default Modal;
2
That is because constructor function runs only once here. So even if the updated state is passed to child component, the child component's state does not update because constructor function does not run again. Why don't you directly use it from props?Prakash Sharma
I will do :), I have forgotten that constructor only run once before loading the component.Ivana

2 Answers

0
votes

constructor runs only once. It's suitable for calculating initial state. But this case is what getDerivedStateFromProps hook is for. It allows to calculate a state from props every time a component is updated, including initialization:

static getDerivedStateFromProps(props) {
  return {
        book: props.book,
        show: props.show
  };
}
0
votes

I edited some parts of your code.I am not sure that you are asking this but hope it will enlight you for your problem.

First - Parent component:

import React, {
  Component
} from 'react';
import Modal from './UI/Modal';

class EnteredBooks extends Component {
  constructor(props) {
    super(props)

    this.state = {
      enteredBook:"",
      showModal: false
    }
  }

  detailsHandler = () => {
    this.setState({
      showModal: true
      enteredBook: this.props.enteredBook
    })
  }

  render() {
    let show = this.state.showModal;
    return ( <
      div >
      <
      div className = "product" >
      <
      img src = "{this.props.enteredWatch.bookUrl}" / >
      <
      p > {
        this.props.enteredWatch.bookType
      } < /p> <
      p > euro {
        this.props.enteredWatch.bookPrice
      } < /p> <
      button className = "details-button"
      onClick = {
        this.detailsHandler
      } >
      Details <
      /button> <
      Modal show = {
        this.state.showModal
      }
      watch = {
        this.state.enteredWatch
      }
      /> <
      button className = "buy-button" > Buy < /button> <
      /div> <
      /div>
    );
  }
}

export default EnteredWatches;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Second - Child component:

import React, {
  Component
} from 'react';
import classes from './Modal.css';

class Modal extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      book: "",
      show: ""
    }
  }

  componentWillReceiveProps(props) {
    const {
      book,
      show
    }: this.props;
    if (book !== props.book || show !== props.show) {
      this.setState({
        book: props.book,
        show: props.show
      });
    }
  }

  return ( <
    div >
    <
    div className = "Modal"
    style = {
      {
        transform: this.state.show ? 'translateY(0)' : 'translateY(-100vh)',
        opacity: this.state.show ? '1' : '0'
      }
    } >

    <
    img src = {
      this.state.book.bookUrl
    }
    /> <
    p > {
      this.state.book.bookType
    } < /p> <
    p > {
      this.state.book.watchUrl
    } < /p> <
    button className = "details-button" > Details < /button> <
    button className = "buy-button" > Buy < /b < /
    div > <
    /div>
  );
}
}

PS : Also you can use componentWillReceiveProps(props) event for the parent component.