0

I have tried this same code in another component and "repos" was getting the content of languagesdata.json, but when trying this code in the App component I get the error I describe in the title.

ComponentDidMount doesn't work either that is why I use componentWillMount, but "repos" is still null after fetchLanguageRepos.

I have added the result of some console.logs in order to make it clearer. Here's the code of the component:

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import Login from './components/Login'
import Dashboard from './components/Dashboard'
import PropTypes from 'prop-types'
import languagesdata from './languagesdata.json'
import { fetchLanguageRepos } from './utils/api'
import {BrowserRouter as Router, Route } from 'react-router-dom'

function LanguagesNav ({ selected, onUpdateLanguage}) {
  const languages = ['EU', 'ES', 'EN']

  return (
    <div >
      <h1 className='center-text header-lg'>
        GAUR 2.0
      </h1>
      <ul className='flex-center'>
        {languages.map((language) => (
          <li key={language}>
            <button
              className='btn-clear nav-link'
              style={language === selected ? { color: 'rgb(187, 46, 31)' } : null }
              onClick={() => onUpdateLanguage(language)}>
              {language}
            </button>
          </li>
        ))}
      </ul>
    </div>
  )
}

LanguagesNav.propTypes = {
  selected: PropTypes.string.isRequired,
  onUpdateLanguage: PropTypes.func.isRequired
}

class App extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      selectedLanguage: 'EU',
      repos: null,
      error: null
    }

    this.updateLanguage = this.updateLanguage.bind(this)
  }

  componentWillMount () {
    this.updateLanguage(this.state.selectedLanguage)
  }

  updateLanguage (selectedLanguage) {
    this.setState({
      selectedLanguage,
      error: null
    })

    console.log(selectedLanguage) // ='EU'

    fetchLanguageRepos(selectedLanguage)
      .then((repos) => this.setState({
          repos,
          error: null,
        }),
      console.log(this.state.repos) //=null
    )
      .catch(() => {
        console.warn('Error fetching repos: ', error)

        this.setState({
          error: 'There was an error fetching the repositories.'
        })
      })
    
    console.log(this.state.repos) // =null

  }

  render() {
    const { selectedLanguage, repos, error } = this.state

    console.log(repos) // =null

    return (
      <Router>
        <div className='container'>
          <LanguagesNav
            selected={selectedLanguage}
            onUpdateLanguage={this.updateLanguage}
          />
          <Route
            exact path='/'
            render={(props) => (
              <Login
                repos={repos}
                selectedLanguage={selectedLanguage}
              />
            )}
          />
          <Route
            path='/dashboard'
            render={(props) => (
              <Dashboard
                repos={repos}
                selectedLanguage={selectedLanguage}
              />
            )}
          />
        </div>
      </Router>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)

Here's the code of fetchLanguageRepos:

api.js

export function fetchLanguageRepos () {
  const endpoint = 'app/languagesdata.json'

  return fetch(endpoint)
    .then((res) => res.json())
    .then((data) => {
      if (!data.languages) {
        throw new Error(data.message)
      }

      return data.languages
    })
}

Does anyone know why is this happening here?

Julen Clarke
  • 77
  • 10
  • 1
    Please also share the `fetchLanguageRepos` util function. – Enijar Sep 07 '21 at 16:06
  • Code added, @Enijar. – Julen Clarke Sep 07 '21 at 16:10
  • You're expecting `repos` to be the value from `data.languages` (which is resolved in `fetchLanguageRepos`)? – Enijar Sep 07 '21 at 16:12
  • 2
    this has nothing to do with react-router, can you put the econsole.log in the ".then()" or asynchronously wait for fetchlanduage to resolve before calling console log? – Alexander Hemming Sep 07 '21 at 16:14
  • Correct, @Enijar. – Julen Clarke Sep 07 '21 at 16:15
  • @AlexanderHemming sorry, but I'm not sure where exactly you are referring to, I added a console.log after having called fetchLanguageRepos. Could you please specify better? – Julen Clarke Sep 07 '21 at 16:24
  • 2
    This is the usual mistake people make with asynchronous code; the second `console.log` is running before your asynchronous code finishes running. If you want to see the results of `fetchLanguage()`, you need to do it inside the `.then()` (where you're currently calling `setState()`. – Daniel Beck Sep 07 '21 at 16:27
  • Okay, done. I've added the console.log to the code in the question, the state is still null. @DanielBeck – Julen Clarke Sep 07 '21 at 16:35
  • can you console the json, to see if that exists before it goes into the state? also I meant here : then((repos) => this.setState({ repos, error: null, }); console.log(repos)) .catch(() – Alexander Hemming Sep 07 '21 at 16:38
  • @AlexanderHemming not sure how I can do that, I copy-pasted both the function and the API from a tutorial, hence, I'm not very familiar with the asynchronous syntax, could you please write how to console the json? – Julen Clarke Sep 07 '21 at 16:54
  • 3
    Does this answer your question? [Why calling react setState method doesn't mutate the state immediately?](https://stackoverflow.com/questions/30782948/why-calling-react-setstate-method-doesnt-mutate-the-state-immediately) – Emile Bergeron Sep 07 '21 at 17:05
  • 2
    The state won't be updated immediately after calling `this.setState`, but it will be up to date the next render. Though, the first render will still be `null` so you have to account for it. – Emile Bergeron Sep 07 '21 at 17:07
  • Not sure about this @EmileBergeron, it worked for me before in another component. See https://stackoverflow.com/q/69043195/5464406, here I was getting the data. – Julen Clarke Sep 07 '21 at 17:17
  • 1
    You were actually not getting the `repos` right away, and you were already doing exactly what I explained in my previous comment about accounting for `null` with ` {repos && < LoginForm...` – Emile Bergeron Sep 07 '21 at 17:23
  • 1
    Sorry, you're right. Thanks @EmileBergeron! – Julen Clarke Sep 07 '21 at 17:26
  • ah sorry, so where ti says setState you are setting state with the "json", you then called "console.log" on the state hoping it would show that json, you can console.log(repos) in the ".then" to see if the json exists – Alexander Hemming Sep 07 '21 at 17:30

0 Answers0