Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript React Basics (retired) Stateful Components Creating a Component Class

Matthew Anderson
Matthew Anderson
322 Points

TypeError: Cannot read property 'props' of undefined

Here is my workspace: https://w.trhou.se/7wkhddyoo8 (modified the link, thank you @Steven Parker)

More specifically, here is the offending code:

const Counter = React.createClass({
  propTypes: {
    score: React.PropTypes.number.isRequired,
  },
  render: () => {
    return (
      <div className="counter">
        <button className="counter-action decrement"> - </button>
        <div className="counter-score"> {this.props.score} </div>
        <button className="counter-action increment"> + </button>
      </div>
    );
  }
});  

According to the compiler, props does not exist. However, through the Player SFC, I am passing in the score property to the Counter component:

const Player = (props) => {
  return(
    <div className="player">
      <div className="player-name">
        {props.name}  
      </div>
      <div className="player-score">
        <Counter score={props.score}/>
      </div>
    </div>
  );
};

Thank you!

Edit Console Error:

Uncaught TypeError: Cannot read property 'props' of undefined
    at Constructor.render (eval at transform.run (babel-browser.min.js:4), <anonymous>:53:19)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (react.js:6157)
    at ReactCompositeComponentWrapper._renderValidatedComponent (react.js:6177)
    at ReactCompositeComponentWrapper.wrapper [as _renderValidatedComponent] (react.js:12513)
    at ReactCompositeComponentWrapper.performInitialMount (react.js:5761)
    at ReactCompositeComponentWrapper.mountComponent (react.js:5692)
    at ReactCompositeComponentWrapper.wrapper [as mountComponent] (react.js:12513)
    at Object.mountComponent (react.js:13175)
    at ReactDOMComponent.mountChildren (react.js:11891)
    at ReactDOMComponent._createInitialChildren (react.js:7055)
/favicon.ico Failed to load resource: the server responded with a status of 404 (Not Found)
Steven Parker
Steven Parker
231,268 Points

You can't share a direct URL to your workspace, it's temporary and only exists while you are using it.

But you can use the snapshot function in the workspace and provide the link to that.

Zack Lee
Zack Lee
Courses Plus Student 17,662 Points

the workspace link is not working. can you post the code of all your modules? also you can format your code so its more readable by surrounding it with 3 ticks (```) like so:

```javascript

...code goes here

```

Matthew Anderson
Matthew Anderson
322 Points

Thank you, I wasn't aware I could post markdown here (read, Matt... READ). Also, the link has been modified (https://w.trhou.se/7wkhddyoo8).

Sam Gord
Sam Gord
14,084 Points

found the solution for this, at THIS STAGE of the course . probably things are going to change later ( or already has changed ) but, to fix this at this stage you DON'T have to use ARROW function, write it like this and it works -->

const Counter = React.createClass({
  propTypes: {
    score: React.PropTypes.number.isRequired,
  },
  render: function() {
    return (
      <div className="counter">
        <button className="counter-action decrement"> - </button>
        <div className="counter-score"> {this.props.score} </div>
        <button className="counter-action increment"> + </button>
      </div>
    );
  }
});

5 Answers

Zack Lee
PLUS
Zack Lee
Courses Plus Student 17,662 Points

I think you're getting some sort of binding issue with the "this" keyword in your counter. I'm referencing the workspace I have for this course, but the code is much different because I finished the course.

Try just using "props.score" instead of "this.props.score"

Matthew Anderson
Matthew Anderson
322 Points

Unfortunately, this does not fix the issue. Since Counter is a Class Component, I need the this keyword to handle the current state.

Matthew Anderson
Matthew Anderson
322 Points
Uncaught TypeError: Cannot read property 'props' of undefined
    at Constructor.render (eval at transform.run (babel-browser.min.js:4), <anonymous>:53:19)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (react.js:6157)
    at ReactCompositeComponentWrapper._renderValidatedComponent (react.js:6177)
    at ReactCompositeComponentWrapper.wrapper [as _renderValidatedComponent] (react.js:12513)
    at ReactCompositeComponentWrapper.performInitialMount (react.js:5761)
    at ReactCompositeComponentWrapper.mountComponent (react.js:5692)
    at ReactCompositeComponentWrapper.wrapper [as mountComponent] (react.js:12513)
    at Object.mountComponent (react.js:13175)
    at ReactDOMComponent.mountChildren (react.js:11891)
    at ReactDOMComponent._createInitialChildren (react.js:7055)
/favicon.ico Failed to load resource: the server responded with a status of 404 (Not Found)
Zack Lee
PLUS
Zack Lee
Courses Plus Student 17,662 Points

I would maybe look into updating the syntax for the counter class. I would change it from a class to a function, for me this is just more explicit with the intentions of the component. it would look similar to the syntax of your player component and allows you to pass the props component explicitly.

const Counter = (props) => {
  return (
      <div className="counter">
        <button className="counter-action decrement"> - </button>
        <div className="counter-score"> {this.score} </div>
        <button className="counter-action increment"> + </button>
      </div>
    );
};

Counter.propTypes = {
  score: React.PropTypes.number.isRequired,
}
Matthew Anderson
Matthew Anderson
322 Points

Honestly, this doesn't seem like a good solution to me. The Counter component is Class-based for a reason (as far as I can tell), as it must have the ability to modify its own state. Thank you for the help, but I fear this is treating the symptom rather than the disease.

Matthew Anderson
Matthew Anderson
322 Points

I opted to use class Counter extends React.Component instead of const Counter = React.createClass(). This fixed the problem with this not being defined.

const PLAYERS = [
  {
    name: "Matt Anderson",
    score: 19,
    id: 1
  },
  {
    name: "Josh Waitzkin",
    score: 420,
    id: 2,
  },
  {
    name: "Ray Bradburry",
    score: 666,
    id: 3,
  }
];

const Header = (props) => {
  return(
    <div className="header">
      <h1>{props.title}</h1>
    </div> 
  );
}

Header.propTypes = {
  title: React.PropTypes.string.isRequired,
};

//const Counter = React.createClass({
//  propTypes: {
//    score: React.PropTypes.number.isRequired,
//  },
//  render: () => {
//    return (
//      <div className="counter">
//        <button className="counter-action decrement"> - </button>
//        <div className="counter-score"> {this.props.score} </div>
//        <button className="counter-action increment"> + </button>
//      </div>
//    );
//  }
//});  

class Counter extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return(
      <div className="counter">
        <button className="counter-action decrement"> - </button>
        <div className="counter-score"> {this.props.score} </div>
        <button className="counter-action increment"> + </button>
      </div>
    );
  }
}

Counter.propTypes = {
  score: React.PropTypes.number.isRequired,
};

const Player = (props) => {
  return(
    <div className="player">
      <div className="player-name">
        {props.name}  
      </div>
      <div className="player-score">
        <Counter score={props.score}/>
      </div>
    </div>
  );
};

Player.propTypes = {
  name: React.PropTypes.string.isRequired,
  score: React.PropTypes.number.isRequired,
}

function Application(props) {
  return (
    <div className="scoreboard">
      <Header title={props.title}/>
      <div className="players">
        {props.players.map((player) => {
          return <Player name={player.name} score={player.score} key={player.id}/>
        })}
      </div>
    </div>
  );
}


Application.defaultProps = {
  title: "Scoreboard",
  players: React.PropTypes.arrayOf(React.PropTypes.shape({
    name: React.PropTypes.string.isRequired,
    score: React.PropTypes.number.isRequired,
    id: React.PropTypes.number.isRequired,
  })).isRequired,
};

ReactDOM.render(<Application players={PLAYERS}/>, document.getElementById('container'));
Zack Lee
Zack Lee
Courses Plus Student 17,662 Points

later in the course you'll end up turning counter into a function because you actually don't want it to have its own state. You end up pushing the state to the top level component so that all your state is in one place so its more easily accessible by other components, which is usually best practice. this become clearer when you start keeping track of all player scores in another component to display a leaderboard of sorts. having the state is the top component makes it easy to access. As they say, "a single source of truth."

You will however create a stop watch component that will be a component extended class because the state is not needed elsewhere in the application, so it is left to be its own stateful component.

Liam Lagan
Liam Lagan
10,517 Points

I had a similar error due to mistakenly adding "this" to the wrong function by mistake.

Ari Misha
Ari Misha
19,323 Points

Hiya there! You're receiving the error coz props arent defined. Your Player component needs a props checking or propTypes validation. The name and score needs a validation for propTypes. Do that and you're good to go. (:

~ Ari