Skip to content

react – state undefined when passing child state through parent

I’m trying to learn react and ran into a snag. I’m struggling to update the parent based on the child state. I’ve managed to pass the child state to the parent by binding the child’s state to the same child’s prop when invoked by the parent.

Parent.js

    import React, { Component, setState } from 'react'
import './Parent.css'
import Child from './Child'

export class Parent extends Component {

    constructor(props) {
        super(props)
    
        this.state = {
            childState: false
        }

    }

    checkState(newState){
        console.log(`new state is ${newState}`)
    }
    

    render() {
        return (
            <div class={`parent ${this.state.childState ? 'parent-child-not-clicked' : 'parent-child-clicked'}`}>
                <h1>{this.state.childState === true ? 'true' : 'false'}</h1>
                {/* <Child changeState={(newState)=>{newState === true ? this.setState(prevState => ({childState: prevState.childState+1})):this.setState(prevState => ({childState: prevState.childState-1}))}}></Child> */}
                <Child changeState={(newState) => {console.log(newState)}}></Child>
            </div>
        )
    }
}

export default Parent

Child.js

import React, { Component } from 'react'
import "./Child.css"

export class Child extends Component {

    constructor(props) {
        super(props)
    
        this.state = {
            childState: false
        }
        this.updateState = this.updateState.bind(this)
    }

    updateState(){
        this.setState({
            childState: !this.state.childState
        }, () => {return this.state.childState})
    }
    
    render() {
        return (
            <div className="child">
                <h1>{`child state is ${this.state.childState}`}</h1>
                <div onClick={() => this.props.changeState(this.updateState())}>Click</div>
            </div>
        )
    }
}

export default Child

The console keeps rendering undefined, meaning newState doesn’t contain the boolean value true / false. Would appreciate if anyone can point me in the right direction.

Thanks in adavance

Answer

this.updateState() doesn’t return anything. So nothing is sent to this.props.changeState.

Probably the simplest approach is to remove this.props.changeState from the JSX markup and move it into updateState. Then within updateState define the new state object, update the component’s state with it, and pass it to the prop function. Something like this:

updateState(){
    const newState = {
        childState: !this.state.childState
    };
    this.setState(newState);
    this.props.changeState(newState);
}

Then in the JSX just call updateState (putting less logic inline in the JSX and more in the functions):

<div onClick={this.updateState}>Click</div>

As an aside, while the example shown is clearly a contrived one, tracking the same state in two different places is probably the wrong design. If the parent just needs updates, pass it just the updates that it needs. But if the parent is tracking the state, the child doesn’t need to duplicate that effort. You can remove state from the child entirely and just pass it the values it needs, simplifying the whole thing.