简体   繁体   中英

ReactJS - cannot read this.props.value on state object

I am just starting to learn ReactJS and I have encountered an error upon compilation of my code:

TypeError: Cannot read property 'value' of undefined

The error occurs on this line: count: this.props.value on the file counter.jsx

As you can see, I have tried to use console.log(this.props) on the render function on counter.jsx in order to validate if the props are set. They are set - so I do not know why I cannot access it in the state object in my Counter class.

Question: What am I doing wrong?

counter.jsx:

import React, { Component } from 'react';

class Counter extends Component {
    state = {
        count: this.props.value,
        tags: []
    };

    render(){
        console.log(this.props);
        return (<React.Fragment>
                    <span>{this.formatCount()}</span>
                </React.Fragment>
        );
    }

    formatCount(){
        var { count } = this.state;
        return count === 0 ? <h1>Zero</h1> : count;
    }
}
export default Counter;

index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import 'bootstrap/dist/css/bootstrap.css';

import Counters from './components/counters';

ReactDOM.render(<Counters />, document.getElementById('root'));
registerServiceWorker();

counters.jsx:

import React, {Component} from 'react';
import Counter from './counter';

class Counters extends Component {
    state = {
        counters: [
        {id: 1, value: 4},
        {id: 2, value: 0},
        {id: 3, value: 0},
        {id: 4, value: 0},
        ]
    };
    render(){
        return (
            <div>
            {this.state.counters.map(counter => (<Counter key={counter.id} value={counter.value} selected={true} />))}
            </div>
        );
    }
}

export default Counters;

this in this.props refers the object created by the JSX <Counter {...}/> . So to get an access of this of the instance of Counter class, you need to use constructor function.

constructor(props) {
  super(props);
  this.state = {
    count: props.value,
    tags: []
  };
}

What you have right now to create the state, is pointing to the Counter class itself, not its instances, that is why this.props is undefined . You can do the same, without constructor function, with the help of getDerivedStateFromProps method.

getDerivedStateFromProps is invoked right before calling the render method, both on the initial mount and on subsequent updates. It should return an object to update the state, or null to update nothing.

class Counter extends Component {
  state = {
    count: null,
    tags: []
  };

  static getDerivedStateFromProps(props, state) {
    return {
      count: props.value,
    }
  }

  // ...
}

Try setting the state inside a constructor , I suspect this is broken

 constructor(props) {
   super(props);
   this.state = {
    count: props.value,
    tags: []
   }
}

It is not advised to set the value of state object directly from props. Better do:

state = {
    count: null,
    tags: []
};

componentDidMount() {
    this.setState({ count: this.props.value });
}

Inside counter.jsx, add:

constructor(props) {
    super(props);
} 

You need to add a constructor with 'props' argument, and call super(props). To set state directly using props.

if your would write it like so, i think it shoulk word. you write it this way to verify the value is existing on props, before you consume it.

state = {
        count: this.props.value ? this.props.value : null,
        tags: []
    };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM