Home > Net >  The state in class constructor isn't defined when calling function after render
The state in class constructor isn't defined when calling function after render

Time:06-15

I can't find any info regarding a situation like this, I'm passing p1 props from my App component to state of my Child1 component.

When I call the buttonHandler method to see the state of s1 I get this error:

Child1.js:27 Uncaught TypeError: Cannot read properties of undefined (reading 'state')

Class component "Child1"

import React from "react";
import { setState } from 'react'

class Child1 extends React.Component {
    constructor(props) {
        super(props)
        this.s2 = 0

        this.state = {
           s1: this.props.p1
        }
        console.log(this.state.s1);
    }

    componentDidMount() {
        // console.log('componentDidMount()')
        console.log('s2 = '   this.s2);
        this.s2  = 1

        this.setState(() => ({
            s1: this.props.p1   1
        }))
    }

    buttonHandler() {
        console.log(this.state.s1);
    }

    render() {
        return (
            <>
                <div>
                    <h3>State s1</h3>
                    <h4>{this.state.s1}</h4>
                </div>
                <hr />

                <div>
                    <h3>props from p1 to s2</h3>
                    <h4>{this.s2}</h4>
                </div>

                <hr />

                <div>
                    <button onClick={this.buttonHandler}>Push</button>
                </div>
            </>
        )
    }
}

export default Child1

App.js

import './App.css';
import Child1 from './Child1';

function App() {
  return (
    <>

      <Child1 p1={88} />
    </>
  )
}

export default App;

CodePudding user response:

With class instances, you need to bind the function to the component instance:

// Use arrow syntax (recommended) or bind in the constructor
  buttonHandler = () => {
    console.log(this.state.s1);
  };

CodePudding user response:

There are 3 problems with the above code:

  1. event listener method binding (in buttonHandler method)
  2. initializing state with props (in constructor)
  3. using prop value inside setState (in componentDidMount)

For the event listener binding, as seen in Dennis Valsh's answer:

buttonHandler = () => {
    console.log(this.state.s1);
};

To initialize state with props, its better to use getDerivedStateFromProps.

static getDerivedStateFromProps(props, state) {
    return {s1: props.p1   1};
}

To update state using props, use the callback argument of setState. (See https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous)

setState((state,props) =>{
    return {s1: props.p1   1};
}

However, since what you're trying to do isn't very clear, I'd say you don't need the componentDidUpdate at all & the getDerivedStateFromProps is sufficient.

  • Related