Passing data to components: 'props' returning undefined

I’m working through the “composing components” module, and am hitting an error while following along lesson 3.

There is the parent component “counter”, and child “counters”.

The child component has the following method:

class Counters extends React.Component {
    state = {
        counters: [
            {id: 1, value:0},
            {id: 2, value:0},
            {id: 3, value:0},
            {id: 4, value:0},
            {id: 5, value:0},
        ]
    }

    render() { 
        return <div>
            {this.state.counters.map(counter => 
            <Counter key={counter.id} value={counter.value} id={counter.id} />)}
        </div>;
    }
}

The idea is that the parent, counter, inherits the children’s props:

class Counter extends Component {
  state = {
    count: this.props.value
  };

However, React returns undefined for this in the render method:

render() {
    console.log(this.props.value) //returns undefined
    return (
    <div>
      <span className={this.getBadgeClasses()}>{this.formatCount()}</span>
      <button onClick={this.handleIncrement} className="btn btn-secondary btn-sm">Increment</button>
      </div>
    );
  }

What am I doing wrong? I think I’ve followed along exactly, so perhaps this is an update to React itself since the course was launched?

I copied your code and add it in codesandbox
it’s working fine

1 Like

Here is my code. It was working back then

App.js

import React, { Component } from 'react';
import NavBar from './components/navbar';
import './App.css';
import CounterSet from './components/counterSet';

class App extends Component {
  state = {
    counters: [
      { id: 1, value: 9 },
      { id: 2, value: 2 },
      { id: 3, value: 7 },
      { id: 4, value: 5 },
      { id: 5, value: 0 }
    ]
  }

  render() {
    return (
      <React.Fragment>
        <NavBar
          totalCounters={this.state.counters.filter(c => c.value !== 0).length}
        />
        <main className="container">
          <CounterSet
            onReset={this.handleReset}
            onDelete={this.handleDelete}
            onIncrement={this.handleIncrement}
            onDecrement={this.handleDecrement}
            counters={this.state.counters}
          />
        </main>
      </React.Fragment>
    )
  }

  handleDelete = (counterId) => {
    const counters = this.state.counters.filter(c => c.id !== counterId);
    this.setState({ counters });
  }

  handleIncrement = counter => {
    const counters = [...this.state.counters];
    const index = counters.indexOf(counter);
    counters[index] = { ...counter };
    counters[index].value++;
    this.setState({ counters });
  }

  handleDecrement = counter => {
    const counters = [...this.state.counters];
    const index = counters.indexOf(counter);
    counters[index] = { ...counter };
    counters[index].value--;
    this.setState({ counters });
  }

  handleReset = () => {
    const counters = this.state.counters.map(c => {
      c.value = 0;
      return c;
    });

    this.setState({ counters });
  }
}

export default App;

CounterSet a.k.a. Counters

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

class CounterSet extends Component {

    render() {
        const { onReset, onDelete, onIncrement, onDecrement } = this.props;

        return (
            <div>
                <button onClick={onReset} className="btn btn-primary btn-sm m-2">Reset</button>
                {this.props.counters.map(counter =>
                    <Counter
                        key={counter.id}
                        counter={counter}
                        onDelete={onDelete}
                        onIncrement={() => { onIncrement(counter) }}
                        onDecrement={() => { onDecrement(counter) }}
                    />)}
            </div>
        )
    }
}

export default CounterSet

Counter

import React, { Component } from 'react';

class Counter extends Component {
    state = {
        tags: []
    }

    styles = {
        fontSize: 12,
        fontWeight: 'bold'
    }

    render() {
        return (
            <React.Fragment>
                <h6>Counter #{this.props.counter.id}</h6>
                <div className="row">
                    <div className="col-1">
                        <span className={this.getBadgeClasses()}>{this.formatCount()}</span><br />
                    </div>
                    <div className="col">
                        <button onClick={this.props.onDecrement} className="btn btn-secondary btn-sm m-2" disabled={(this.props.counter.value <= 0) ? "disabled" : ""}>-</button>
                        <button onClick={this.props.onIncrement} className="btn btn-secondary btn-sm m-2">+</button>
                        <button onClick={() => { this.props.onDelete(this.props.counter.id) }} className="btn btn-danger btn-sm m-2">×</button>
                    </div>
                </div>
                <br />
            </React.Fragment>
        );
    }

    renderTags() {
        if (this.state.tags.length === 0) return <p className="m-2">There is no tag to display.</p>;

        return (
            <ul className="m-2">
                {this.state.tags.map(tag => <li key={tag}>{tag}</li>)}
            </ul>
        )
    }

    getBadgeClasses() {
        let classes = "badge m-2 badge-";
        classes += this.props.counter.value === 0 ? "warning" : "primary";
        return classes;
    }

    formatCount() {
        const { value } = this.props.counter;
        return value === 0 ? 'Zero' : value;
    }
}

// Move this to secure place later
// TXkgY3JlZGl0IGNhcmQgbnVtYmVyIGlzIDAxMjMgNDU2NyA4OTAxIDIzNDUgYW5k
// IENWViBpcyAxMjMNClBJTiBpcyA5ODc2DQpDb3B5IHRoaXMgaW4gYSBzZWN1cmUg
// cGxhY2UgbGF0ZXI=

export default Counter

1 Like