0

I am using react with ES6 and want to reuse a variable at class level. I get an error:

bundle.js:29225 Uncaught TypeError: Cannot read property 'tempUnits' of undefined

My code is here

class WeatherList extends Component {
  constructor(){
    super();
    this.tempUnits = 'C'; // <== initialise it here
  }


  renderWeather(cityData) {
    console.log('tempunits', this.tempUnits); // <== blows up here
    const name = cityData.city.name;
    const temps = _.map(cityData.list.map(weather => weather.main.temp), (temp) => temp-273);
    const pressures = cityData.list.map(weather => weather.main.pressure);
    const humidities = cityData.list.map(weather => weather.main.humidity);
    const { lon, lat } = cityData.city.coord;

    return (
      <tr key={name}>
        {/* <td><GoogleMap lon={lon} lat={lat} /></td> */}
        {/* <== Use it here */}
        <td><Chart data={temps} color="orange" units="{this.tempUnits}" /></td>
        <td><Chart data={pressures} color="green" units="hPa" /></td>
        <td><Chart data={humidities} color="black" units="%" /></td>
      </tr>
    );
  }

  render() {
    return (
      <table className="table table-hover">
        <thead>
          <tr>
            <th>City</th>
            {/* <== Reuse it here again */}
            <th>Temperature ({this.tempUnits})</th>
            <th>Pressure (hPa)</th>
            <th>Humidity (%)</th>
          </tr>
        </thead>
        <tbody>
          {this.props.weather.map(this.renderWeather)}
        </tbody>
      </table>
    );
  }
}

Questions I want to reuse the tempUnits variable across functions within the class. How do I do this?

Banoona
  • 1,470
  • 3
  • 18
  • 32
  • 1
    You could bind `renderWeather` to `this` in the constructor, or use an arrow function as class property `renderWeather = (cityData) => { ... }` instead. – Tholle Nov 08 '18 at 12:18
  • See https://reactjs.org/docs/handling-events.html (especially the part about `bind` and the alternatives to it). – str Nov 08 '18 at 12:22
  • Thanks. As per the above link I would go for bnding in the constructor: 'We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.' where 'this sort of problem' is caused by tue fat arrow functions. – Banoona Nov 09 '18 at 14:46

2 Answers2

0

Add the following line. It will replace the renderWeather function with a new instance, which will be bound to the class level context.

this.renderWeather = this.renderWeather.bind(this);

Full code:

class WeatherList extends Component {
  constructor(){
    super();
    this.tempUnits = 'C';
    this.renderWeather = this.renderWeather.bind(this);
  }
Banoona
  • 1,470
  • 3
  • 18
  • 32
0

Instead of directly initializing the variable in constructor method you should add it to the state of the component. Add the follow snippet underneath the constructor method;

state = {
  "tempUnits": "C",
}

You'll have to bind the function this.renderWeather to the this like this.renderWeather.bind(this)

After that you can access tempUnit like this.state.tempUnits.

If you want to change tempUnits, use;

this.setState({ tempUnits: "F" }); 
Haseeb Burki
  • 676
  • 2
  • 8
  • 23