0

Edit. I asked the question but failed to make it so people understand what I am asking. So let's put some code in.

Parent component key parts:

constructor(props){
  super(props);
  ...
  this.state = {
    hourMinute: 1200
  }
}
.....
handleChange(hourMinute){
    this.setState({hourMinute: hourMinute});
}
.....
<HourMinute onChange={this.handleChange} hourMinute={this.state.hourMinute} />

Child component key parts:

constructor(props){
    super(props);
    ....
    this.state = {
        hour: 5, // 0..24
        minute: 10, // 0..59
    }
}

static getDerivedStateFromProps(props, state) {
    const hourMinute = props.hourMinute;
    const hour = Math.floor(hourMinute/60);
    const minute = hourMinute - 60 * hour;

    return {
        hour: hour, // 0..24
        minute: minute // 0..59
    }        
}

.......
handleChange(e){
    this.setState({
       [e.target.id]: e.target.value
    });

    if(valid) this.props.handleChange(hourMinute);
}
.......

<input id="hour" type="number" inputMode="numeric" 
       step="1" pattern="[0-9]*" maxLength="2" autoComplete="off" 
       className="form-control"
       value={this.state.hour}
       onChange={this.handleChange}/>

<input id="minute" type="number" inputMode="numeric" 
       step="1" pattern="[0-9]*" maxLength="2" autoComplete="off" 
       className="form-control"
       value={this.state.minute}
       onChange={this.handleChange}/>

As componentWillReceiveProps is depreciated and considered unsafe, and for getDerivedStateFromProps is explained that it should not be used in a way to copy received prop to state, what should be the right concept for this kind of situations?

Nebojsa
  • 133
  • 1
  • 8

2 Answers2

0

You can simply send it as a prop to the Child component and with it send another function as prop to be used by Child to update Parent whenever the value is valid as you are saying for example:

class Parent extends Component {
    constructor(props) {
        super(props);
        this.state = {minuteHour: 0};
        this.handleValidNumber = this.handleValidNumber.bind(this);
    }

    handleValidNumber() {
        // ...
    }

    render() {
        return (
            <div className="SuggestionBox">
                <Child minuteHour={this.state.minuteHour} handleValidNumber={this.handleValidNumber} />
            </div>
        );
    }
}

then in Child according to your logic you can call this.props.handleValidNumber() and in case the value of minuteHour changes in parent by other components as you saying it will update its state and automatically re-render and the new props values would be sent to Child.

Class Child extends Component {
    constructor(props) {
        super(props);
        this.handleButtonClick = this.handleButtonClick.bind(this);
    }

    handleButtonClick() {
        // do some logic using this.props.minuteHour (received as prop from parent)
        // then you may send it back to parent as a function parameter using this.props.handleValidNumber(this.props.minuteHour) 
    }

    render() {
        <div>
            <button onClick={this.handleButtonClick}> Click button </button>
        </div>
    }
}
Mohamed Ibrahim Elsayed
  • 2,734
  • 3
  • 23
  • 43
  • Thank you for answer, but that is not the issue. The problem is how to take receiving prop (for example minuteHour), manage it in child component separately from Parent, and return it to parent on certain events. Also, if value is changed in parent component, child should be updated. – Nebojsa Dec 17 '18 at 19:28
  • What do you mean by "return it to parent"? Do you mean passing it to a function in the parent component from the child? – Mohamed Ibrahim Elsayed Dec 17 '18 at 19:29
  • the code in the answer above already updates the child when the value in parent is changed as the variable `minuteHour` is part of the `state` of the component, so whenever this variable is changed so the `state` of the component is changed and it `re-renders` and when it re-renders, it causes all its children components re-render and send them new `props` values, so the child would be updated too. – Mohamed Ibrahim Elsayed Dec 17 '18 at 19:39
  • Yes. But that is easy part. Problem is how to update child whenever value in parent is changed, then send value using props to child, and then manage it in child component within child state. – Nebojsa Dec 17 '18 at 19:40
  • Yes that works in case that props is the only source, but I need to copy props to state of child component, so I can manage it in more complex way. – Nebojsa Dec 17 '18 at 19:42
  • I think copying props from parent to state of child is considered an anti-pattern in React https://stackoverflow.com/a/47341539/3582996 what are you trying to achieve, I mean why not use props directly? I have updated the answer with an example code of what could be in child component – Mohamed Ibrahim Elsayed Dec 17 '18 at 19:46
  • Yes you are right about anti-pattern, that is why I am confused how to do this :)... I updated my question with simplified code so you better understand my issue. But the bottom line is that I would like to fully simplify Parent component and remove any details from it, just to have simple number, while all logic and management to be done in child. – Nebojsa Dec 18 '18 at 09:59
  • **I would like to fully simplify Parent component and remove any details from it, just to have simple number, while all logic and management to be done in child.** I think this is not the way you should always be thinking in React as in React the higher level of a component in the tree, the more responsibility it has, so the parent component should always have more responsibility, and thus bigger state than its children components, I think in your case your best bet is to `lift the state up`, I mean lift the state of this child component to its parent's state and pass those variables as props. – Mohamed Ibrahim Elsayed Dec 18 '18 at 21:39
  • 1
    Thank you @Mis94 for your continuous comments. I was thinking about lifting the state up, but it would complicate a lot of things in number of places where i use the same component. I found the solution, or better to say, I think that I found the solution. I documentation they actually say "if you unconditionally copy props to state than it is anti-pattern". I don't do that, there is number of conditions that I apply. Component is working as I expect, so I will keep it like that for now :)... I cannot accept your answer as it is not what I need, but I will try to vote it up. – Nebojsa Dec 19 '18 at 10:17
0

Try this:

class Parent extends Component {
    constructor(props) {
        super(props);
        this.state = {propToBeSentToChild:""};
    }

    handlechangedProp=(changedProp)=> {
        // ...
    }

    render() {
        return (
            <div className="SuggestionBox">
                <Child propForChild={this.state.propToBeSentToChild} handlechangedProp={this.handlechangedProp} />
            </div>
        );
    }
}

And in the Child Component, do :

Class Child extends Component {
    constructor(props) {
        super(props);

    }

    handleButtonClick=()=> {
        let changedProp = this.props.propForChild;
        //do whatever you want to do with this changed prop and then pass
        //it back to the parent component's method
        this.props.handleChangedProp(changedProp) 
    }

    render() {
        <div>
            <button onClick={this.handleButtonClick}> Click button </button>
        </div>
    }
}