Problems with React rendering twice

I’m having some problems with the following code.

Basically, I’m fetching data from the FCC weather api, then calling setState to update the state. But when I try rendering the data I’m getting a whole mess of errors. I tried using console.log to log “hi” and it’s rendering twice, first undefined and then “hi”. I’m sure the double rendering is causing the problem. Can anyone help me with this?

import React from 'react'
import './Weather.css'

class Weather extends React.Component {
  constructor(props) {
    super(props)
    
    this.state = {
      latitude: 0,
      longitude: 0,
      weather: {}
    }
  }

  componentDidMount() {
    if (window.navigator.geolocation) { 
      navigator.geolocation.getCurrentPosition((position) => {
        this.getWeatherData(position.coords.latitude, position.coords.longitude)
      })
    }
  }

  getWeatherData(latitude, longitude) {
    const weatherapi = "https://fcc-weather-api.glitch.me/api/current?"

    fetch(`${weatherapi}lat=${latitude}&lon=${longitude}`)
      .then(response => response.json())
      .then(data => {
        this.setState({
          latitude,
          longitude,
          weather: data
        })
      })
  }
  
  render() {
    return (
      <div className="weather">
        <h3>Weather</h3>
        {console.log(this.state.weather.main.temp)}
      </div>
    );
  }
}

export default Weather

What do the errors say?

Reading through your code, it seems fine. Can you put it in a codepen?

Absolutely.

Here’s the Codepen: https://codepen.io/mikesuchor/pen/eopRjX

And here’s the errors:

Weather.js:43 Uncaught TypeError: Cannot read property ‘temp’ of undefined
at Weather.render (Weather.js:43)
at finishClassComponent (react-dom.development.js:15288)
at updateClassComponent (react-dom.development.js:15243)
at beginWork (react-dom.development.js:16233)
at performUnitOfWork (react-dom.development.js:20253)
at workLoop (react-dom.development.js:20294)
at HTMLUnknownElement.callCallback (react-dom.development.js:147)
at Object.invokeGuardedCallbackDev (react-dom.development.js:196)
at invokeGuardedCallback (react-dom.development.js:250)
at replayUnitOfWork (react-dom.development.js:19477)
at renderRoot (react-dom.development.js:20407)
at performWorkOnRoot (react-dom.development.js:21331)
at performWork (react-dom.development.js:21241)
at performSyncWork (react-dom.development.js:21215)
at requestWork (react-dom.development.js:21070)
at scheduleWork (react-dom.development.js:20883)
at scheduleRootUpdate (react-dom.development.js:21578)
at updateContainerAtExpirationTime (react-dom.development.js:21604)
at updateContainer (react-dom.development.js:21672)
at ReactRoot.push…/node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render (react-dom.development.js:21985)
at react-dom.development.js:22137
at unbatchedUpdates (react-dom.development.js:21460)
at legacyRenderSubtreeIntoContainer (react-dom.development.js:22133)
at Object.render (react-dom.development.js:22208)
at Module…/src/index.js (index.js:6)
at webpack_require (bootstrap:781)
at fn (bootstrap:149)
at Object.0 (index.js:6)
at webpack_require (bootstrap:781)
at checkDeferredModules (bootstrap:45)
at Array.webpackJsonpCallback [as push] (bootstrap:32)
at main.chunk.js:1
render @ Weather.js:43
finishClassComponent @ react-dom.development.js:15288
updateClassComponent @ react-dom.development.js:15243
beginWork @ react-dom.development.js:16233
performUnitOfWork @ react-dom.development.js:20253
workLoop @ react-dom.development.js:20294
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
replayUnitOfWork @ react-dom.development.js:19477
renderRoot @ react-dom.development.js:20407
performWorkOnRoot @ react-dom.development.js:21331
performWork @ react-dom.development.js:21241
performSyncWork @ react-dom.development.js:21215
requestWork @ react-dom.development.js:21070
scheduleWork @ react-dom.development.js:20883
scheduleRootUpdate @ react-dom.development.js:21578
updateContainerAtExpirationTime @ react-dom.development.js:21604
updateContainer @ react-dom.development.js:21672
push…/node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:21985
(anonymous) @ react-dom.development.js:22137
unbatchedUpdates @ react-dom.development.js:21460
legacyRenderSubtreeIntoContainer @ react-dom.development.js:22133
render @ react-dom.development.js:22208
./src/index.js @ index.js:6
webpack_require @ bootstrap:781
fn @ bootstrap:149
0 @ index.js:6
webpack_require @ bootstrap:781
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.chunk.js:1
Show 2 more frames
index.js:1446 The above error occurred in the component:
in Weather (at Dashboard.js:16)
in div (at Dashboard.js:15)
in div (at Dashboard.js:12)
in div (at Dashboard.js:11)
in Dashboard (at App.js:8)
in div (at App.js:7)
in App (at src/index.js:6)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
console.(anonymous function) @ index.js:1446
logCapturedError @ react-dom.development.js:17848
logError @ react-dom.development.js:17884
update.callback @ react-dom.development.js:18907
callCallback @ react-dom.development.js:17072
commitUpdateEffects @ react-dom.development.js:17112
commitUpdateQueue @ react-dom.development.js:17102
commitLifeCycles @ react-dom.development.js:18140
commitAllLifeCycles @ react-dom.development.js:19642
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
commitRoot @ react-dom.development.js:19866
(anonymous) @ react-dom.development.js:21414
unstable_runWithPriority @ scheduler.development.js:255
completeRoot @ react-dom.development.js:21413
performWorkOnRoot @ react-dom.development.js:21336
performWork @ react-dom.development.js:21241
performSyncWork @ react-dom.development.js:21215
requestWork @ react-dom.development.js:21070
scheduleWork @ react-dom.development.js:20883
scheduleRootUpdate @ react-dom.development.js:21578
updateContainerAtExpirationTime @ react-dom.development.js:21604
updateContainer @ react-dom.development.js:21672
push…/node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:21985
(anonymous) @ react-dom.development.js:22137
unbatchedUpdates @ react-dom.development.js:21460
legacyRenderSubtreeIntoContainer @ react-dom.development.js:22133
render @ react-dom.development.js:22208
./src/index.js @ index.js:6
webpack_require @ bootstrap:781
fn @ bootstrap:149
0 @ index.js:6
webpack_require @ bootstrap:781
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.chunk.js:1
Show 7 more frames
react-dom.development.js:21301 Uncaught TypeError: Cannot read property ‘temp’ of undefined
at Weather.render (Weather.js:43)
at finishClassComponent (react-dom.development.js:15288)
at updateClassComponent (react-dom.development.js:15243)
at beginWork (react-dom.development.js:16233)
at performUnitOfWork (react-dom.development.js:20253)
at workLoop (react-dom.development.js:20294)
at renderRoot (react-dom.development.js:20374)
at performWorkOnRoot (react-dom.development.js:21331)
at performWork (react-dom.development.js:21241)
at performSyncWork (react-dom.development.js:21215)
at requestWork (react-dom.development.js:21070)
at scheduleWork (react-dom.development.js:20883)
at scheduleRootUpdate (react-dom.development.js:21578)
at updateContainerAtExpirationTime (react-dom.development.js:21604)
at updateContainer (react-dom.development.js:21672)
at ReactRoot.push…/node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render (react-dom.development.js:21985)
at react-dom.development.js:22137
at unbatchedUpdates (react-dom.development.js:21460)
at legacyRenderSubtreeIntoContainer (react-dom.development.js:22133)
at Object.render (react-dom.development.js:22208)
at Module…/src/index.js (index.js:6)
at webpack_require (bootstrap:781)
at fn (bootstrap:149)
at Object.0 (index.js:6)
at webpack_require (bootstrap:781)
at checkDeferredModules (bootstrap:45)
at Array.webpackJsonpCallback [as push] (bootstrap:32)
at main.chunk.js:1
render @ Weather.js:43
finishClassComponent @ react-dom.development.js:15288
updateClassComponent @ react-dom.development.js:15243
beginWork @ react-dom.development.js:16233
performUnitOfWork @ react-dom.development.js:20253
workLoop @ react-dom.development.js:20294
renderRoot @ react-dom.development.js:20374
performWorkOnRoot @ react-dom.development.js:21331
performWork @ react-dom.development.js:21241
performSyncWork @ react-dom.development.js:21215
requestWork @ react-dom.development.js:21070
scheduleWork @ react-dom.development.js:20883
scheduleRootUpdate @ react-dom.development.js:21578
updateContainerAtExpirationTime @ react-dom.development.js:21604
updateContainer @ react-dom.development.js:21672
push…/node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render @ react-dom.development.js:21985
(anonymous) @ react-dom.development.js:22137
unbatchedUpdates @ react-dom.development.js:21460
legacyRenderSubtreeIntoContainer @ react-dom.development.js:22133
render @ react-dom.development.js:22208
./src/index.js @ index.js:6
webpack_require @ bootstrap:781
fn @ bootstrap:149
0 @ index.js:6
webpack_require @ bootstrap:781
checkDeferredModules @ bootstrap:45
webpackJsonpCallback @ bootstrap:32
(anonymous) @ main.chunk.js:1

So it seems pretty plain to see that the Component is rendering before componentDidMount and is breaking the program as I’m trying to write some json data from this.state.weather that doesn’t exist yet but I don’t know how to fix this. When changing the console.log to just plain text or something more generic here is what is logged:

{console.log(this.state.weather.main)}
Logged: undefined
Logged: {temp: -1.18, pressure: 1009, humidity: 60, temp_min: -3.33, temp_max: 0.56}

{console.log(“hi”)}
Logged: “hi”
Logged: “hi”

Your component is rendering straight away, before the API call is completed and therefore cannot render the data. setState() can also take time to actually set the state.
Once the state of your application has been updated, any components with an updated state will get re-rendered and this is where the second console.log outputs are coming from.

You can use conditional rendering to only render the data once it has been fetched and saved in the state.

I use this a lot, great writeup on different ways to do conditional rendering in React.

render() {
    if(!this.state.weather.main.temp) {
    return (
      <div className="weather">
        <h3>Weather</h3>
        Loading...
      </div>
    );
}else{
    return (
      <div className="weather">
        <h3>Weather</h3>
        {this.state.weather.main.temp}
      </div>
    );
  }

}
1 Like

Very cool, thanks!

Do you recommend declaring empty initial values in state as null? I used an empty object,

I do the same as you, initialize to empty string/array/object.

But I am not sure what the best practices are.

Your code is perfectly fine but needs something. just make life cycle method an asynchronous function
using
async componentDidMount …

1 Like