Getting error while updating state( skipping the constructor for state in react)

I am creating simple react program where I have created an array of language and mapping it to create list items and when the user clicks on list item of language it should call updateLanguage method and update state accordingly but I am getting an setState undefined error . Can anyone help me to resolve an issue.

code ::

import React, { Component } from 'react';

class Popular extends React.Component {
   state = {
      selectedLanguage: 'All'
   };

 updateLanguage() {
    this.setState(lang => ({
      selectedLanguage: lang 
    }));
  }

   render() {
      const languages = ['All', 'JavaScript', 'Ruby', 'Java', 'CSS', 'Python'];
      console.log();
      
      return (
        <div>
          <ul className = 'languages'>
          <p> Selected Language: {this.state.selectedLanguage} </p>
            {languages.map((lang) => {
              return (
                <li 
                  onClick={this.updateLanguage} 
                  key={lang}> 
                  {lang}
                </li>
              )
            })}
          </ul>
          </div>
      );
   }
}

export default Popular;

error ::

OK,

one problem is that you really need a constructor to initialize state, something like this:

  constructor() {
    super()
    this.state = {
      selectedLanguage: 'All'
    }
  }

That is pretty standard, boilerplate React.

The next problem (the one for which you are seeing an error) is that your function doesn’t know what “this” is when you call it. You need to bind this to that function. There are couple of ways to do this. This is a common way, doing it in the constructor:

  constructor() {
    super()
    this.state = {
      selectedLanguage: 'All'
    }
    this.updateLanguage = this.updateLanguage.bind(this);
  }

OK, the next problem is that your function can’t get the data, so we need to pass it in:

  updateLanguage(lang) {

and we need to properly put it into state:

  updateLanguage(lang) {
    this.setState({
      selectedLanguage: lang 
    })
  }

OK, lastly we need to pass the data into the function from our JSX. If we change our onClick to

onClick={this.updateLanguage(lang)} 

BAAAD things will happen because it will call this function every time the compnent renders (because the parentheses keep it from being passed as an argument and cause it to be evaluated) . So, we need to pass it an anonymous function:

onClick={() => this.updateLanguage(lang)} 

That should work. Here is a working pen.

1 Like

I guess technically you can declare state the way you did. I still think a constructor is a better way to go - it is what people expect to see and it is there if you need it for other things.

Hello Kevin, Thanks for replying. With constructor I am able to do. But I want to do it without using constructor which is new way and effective way to declare state.

Questions here. First, why do you want to do it that way? What is the advantage?

As far as it being the “new” way is debatable. My understanding is that this is dependent on not finalized JS standards. And according to React’s docs:

The only place where you can assign this.state is the constructor.

and in another place in their docs:

The constructor is the right place to initialize state. To do so, just assign an object to this.state; don’t try to call setState() from the constructor. The constructor is also often used to bind event handlers to the class instance.

So, if it is the “new” way to do React, someone should tell the people at React.

and effective way to declare state.

But is it somehow more effective? We have an effective way to declare state, the currently accepted best practice.

But it works (I assume) because Babel transpiles it into essentially the same thing.

The advantage of using the constructor is that initializing state is a lifecycle event and the constructor in React is basicallical a lifecycle function. You are putting lifecycle things in a lifecycle function instead of hanging off on their own in no-man’s land.

If you or anyone else can show me that your “new” way is a better way, I’ll wave the flag. But people tend to get excited about new features and often tout them as the “cool new” way to do things. I like to wait until they are 1) fully supported and 2) shown to be an improvement for the specific usage. As it is now, the people at React haven’t seemed to have adopted it.

Do you have any source that says that it is the new and proper way to do it or is better? I can’t seem to find anything other than a few people saying, “Hey, this is cool!” I don’t care about “cool”, I care about “best practices”.

But if you must do it without a constructor, then it is possible. But now you can’t bind this to the function in the constructor because there is not constructor. There are ways around this, but one easy way would be to use an arrow function. A standard function creates it’s own this therefore creating the need to bind this. But if you use an arrow function, it will inherit the this from the class.

class Popular extends React.Component {
  state = {
    selectedLanguage: 'All'
  }

  updateLanguage = (lang) => {
    this.setState({
      selectedLanguage: lang 
    })
  }
// ...

The pen is here.

The other option would be to keep the standard function and bind this down in the JSX, like:

onClick={this.updateLanguage.bind(this, lang)} 

Hey kevin, Thanks for replying check out link below from official site of react.

https://discuss.reactjs.org/t/skipping-the-constructor-for-state/4125

That is a discussion forum, not the official docs. And the lukewarm consensus of one person from two years ago seems to be, “I guess it can’t hurt, it’s less typing.”

The official React docs have not included this.

Does it work? Yes.
Will it always work? Probably.
Is it the currently accepted best practice? No.
Will it become the accepted best practice in certain cases? Who knows.

Again, I don’t like it because it takes what is a lifecycle event out of a lifecycle function and puts it in no-man’s land. I understand what it is doing - it is just applying a state object directly to this. That makes sense. But as far as I can tell it gains nothing except a little less typing. It also opens up the possibility of confusion. Maybe one day this will be the way that everyone does it. But it isn’t now. Web dev changes so fast, splintering in so many directions, that you need to be careful about chasing trends. You need to be especially careful about chasing trends that aren’t part of the spec yet.

2 Likes