Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why this.setState is undefined in React ES6 class? #283

Closed
imevro opened this issue Jun 1, 2015 · 42 comments
Closed

Why this.setState is undefined in React ES6 class? #283

imevro opened this issue Jun 1, 2015 · 42 comments

Comments

@imevro
Copy link

imevro commented Jun 1, 2015

Hi, I trying to use ES6's classes for React (syntax as class X extends React.Component) and alt.js as flux library. When something changed in my store, my view calls onChange, but it throws error Uncaught TypeError: this.setState is not a function.

My React component:

import React from 'react';
import { Router, Link } from 'react-router';

import PropertiesActions from '../../actions/properties';
import PropertiesStore from '../../stores/properties';
import PropertiesComponent from '../../components/properties/list';

// Module
class PropertiesView extends React.Component {
  constructor(props) {
    super(props);

    this.state = PropertiesStore.getState();
  }

  componentDidMount() {
    PropertiesStore.listen(this.onChange);

    PropertiesActions.getList();
  }

  componentWillUnmount() {
    PropertiesStore.unlisten(this.onChange);
  }

  onChange(state) {
    this.setState(state);
  }

  render() {
    return (<PropertiesComponent properties={this.state.properties} {...this.props} />)
  }
};

PropertiesView.contextTypes = {
  router: React.PropTypes.func
};

// Export
export default PropertiesView;
@troutowicz
Copy link
Contributor

React components using ES6 classes no longer autobind this to non React methods. In your constructor, add:

this.onChange = this.onChange.bind(this)

@imevro
Copy link
Author

imevro commented Jun 1, 2015

@troutowicz thanks!

@imevro imevro closed this as completed Jun 1, 2015
@LePetitDev
Copy link

@troutowicz 👏

@jonnywyatt
Copy link

@troutowicz - nice one, saved me some time thanks

@gchandrasa
Copy link

@troutowicz thank you, you really save my day!

@goatslacker
Copy link
Owner

FYI Make sure you do this.onChange = this.onChange.bind(this) in your constructor: https://medium.com/@goatslacker/react-0-13-x-and-autobinding-b4906189425d

@jdlehman
Copy link
Collaborator

You can also use this decorator

@goatslacker
Copy link
Owner

Disclaimer ^^ requires a polyfill and I think it doesn't work on IE8.

@kiki-le-singe
Copy link

@troutowicz thanks!

@lenage
Copy link

lenage commented Jul 13, 2015

@troutowicz Thanks, it works like charm!

@troutowicz
Copy link
Contributor

😊

@kiki-le-singe
Copy link

You can also use the following code by combining ES6 and ES7:

Note: Don't forget to setup Babel for this babelify

onChange = (state) => {
  this.setState(state);
}

See React on ES6+ from Steven Luscher

benjaffe added a commit to benjaffe/react that referenced this issue Sep 20, 2015
The autobinding doesn't happen with non React methods in ES6 at least. The docs led me astray, so this clarification would make them a bit more technically correct. Ideally there should be an entire sentence added at the end of the paragraph to clarify more specifically when React does and doesn't autobind to its component instance.

Discovered this solution here: "React components using ES6 classes no longer autobind this to non React methods." goatslacker/alt#283
@mgrodek
Copy link

mgrodek commented Dec 4, 2015

Aaaagrh.. that was killing me! Thanks a lot for this.

@arcseldon
Copy link

👍

@arcseldon
Copy link

@jdlehman / @kiki-le-singe - Thank you for point the arrow syntax option which auto-binds enclosing scope this.

liubiantao referenced this issue in 2remote/yaopai-mobile Dec 26, 2015
@aryalprakash
Copy link

thanks!

@iOSQiao
Copy link

iOSQiao commented Mar 16, 2016

very good.

@kubante
Copy link

kubante commented Mar 18, 2016

saved my morning

@thecodecafe
Copy link

Hi! @troutowicz your answer seemed to have helped a lot of users on this issue except me of course, now i get the following error Cannot read property 'bind' of undefined please what could be the issue? thanks, eagerly awaiting your response!

@kevinSuttle
Copy link

Updated link: http://babeljs.io/blog/2015/06/07/react-on-es6-plus

@thecodecafe
Copy link

thecodecafe commented May 12, 2016

Thanks @kevinSuttle problem solved,

Just in case anybody like me comes here you simply bind the object to your desired method like so.
construct(){ self(); this.yourMethod = this.yourMethod.bind(this); }
And you're done!

@shadrech
Copy link

shadrech commented Jun 10, 2016

I used the arrow function to bind this to the onChange method but keep getting the 'Unexpected token' error. Even in the Steven Luscher blog post (updated link above), the code on the Arrow Function section gives same error. No sure what I'm doing wrong @troutowicz @kevinSuttle @mrbarde

@kevinSuttle
Copy link

@shadrech This is phoned-in response, but I did come across this package that handles binding for you using ES7 decorators. https://github.com/andreypopp/autobind-decorator

@shadrech
Copy link

@kevinSuttle Thanks for the package, will try it out.
But why is the arrow function not working? I sit to do with the ES version I'm using?

@nodox
Copy link

nodox commented Jul 5, 2016

This was super helpful. autobind came in handy when I needed to bind my methods

@TeodorKolev
Copy link

none of this works for me

@goatslacker
Copy link
Owner

@TeodorKolev why is it not working?

@Pines-Cheng
Copy link

or ::this.onChange ,this is more convenient.

@thecodecafe
Copy link

@TeodorKolev you could try using react autobind, works like magic.https://www.npmjs.com/package/react-autobind

@hanserino
Copy link

hanserino commented Aug 30, 2016

@troutowicz Thanks! Worked like a charm!!
To all others implementing this, note that adding the onChange binding itself won't fix anything. You'll need to add your specific function you want to bind to the constructor. If it's a resize handling function, do this.handleResize = this.handleResize.bind(this);

@jasan-s
Copy link

jasan-s commented Sep 11, 2016

Hey guys I keep getting this error when using this line of code this.handleRequestOpen({open: true}):

Uncaught TypeError: Cannot read property 'handleRequestOpen' of undefined

Its not from binding I think. Any thoughts? Initially I was just trying to call
this.setState({ open: false }). Should it know what "this" is?

My code:

class HomeContainer extends Component {

  static propTypes = {
    authError: PropTypes.string,
    removeError: PropTypes.func.isRequired,
    fetchingUserSuccess: PropTypes.func.isRequired,
    authUser: PropTypes.func.isRequired
  }

  static contextTypes = {
    router: PropTypes.object.isRequired
  }

  constructor (props) {
    super(props)
    this.state = {
      open: false
    }
  }
  componentDidMount () {
    firebaseAuth.getRedirectResult().then((authUser) => {
    // The signed-in user info.
      console.log('User Data from Oauth Redirect: ', authUser)
      const userData = authUser.user.providerData[0]
      const userInfo = formatUserInfo(userData.displayName, userData.photoURL, userData.email, authUser.user.uid)
      return (this.props.fetchingUserSuccess(authUser.user.uid, userInfo))
    })
    .then((user) => {
      return saveUser((user.user))
    })
    .then((user) => {
      return (this.props.authUser(user.uid))
    }).then((user) => {
      this.context.router.replace('feed')
    }).catch(function (error) {
      // Handle Errors here.
      const errorCode = error.code
      const errorMessage = error.message
      // The email of the user's account used.
      const email = error.email
      // The firebase.auth.AuthCredential type that was used.
      const credential = error.credential
      // if error is that there is already an account with that email
      if (error.code === 'auth/account-exists-with-different-credential') {
        // console.log(errorMessage)
        firebaseAuth.fetchProvidersForEmail(email).then(function (providers) {
           // If the user has several providers,
          // the first provider in the list will be the "recommended" provider to use.
          console.log('A account already exists with this email, Use this to sign in: ', providers[0])
          if (providers[0] === 'google.com') {
            this.handleRequestOpen({open: true})
          }
        })
      }
    })
  }

  handleRequestOpen = (state) => {
    this.setState(state)
  }

  handleRequestClose = () => {
    this.setState({
      open: false
    })
  }
  render () {
    return (
      <div>
      <Snackbar
          open={this.state.open}
          message= 'A account already exists with this email'
          autoHideDuration={4000}
          onRequestClose={this.handleRequestClose.bind(this)}/>
      <Home />
      </div>
    )
  }
}

@thecodecafe
Copy link

@jasan-s If you want any method(function) within your class to work, you need to bind it, in your constructor enter the following code, this.handleRequestOpen = this.handleRequestOpen.bind(this);
you should do the same for handle request close, hope this helped? :D

@jasan-s
Copy link

jasan-s commented Sep 12, 2016

@mrbarde thanks. I instead changed my older syntax of using function to newer arrow function () => {}
and that solved the issue.

@Labyrins
Copy link

Thank you so much, dudes. I solved my problem.

simnalamburt added a commit to simnalamburt/pen that referenced this issue Jan 10, 2017
1.  Replace `React.createClass` with `React.Component`

2.  Perform prop validation

3.  Remove the useage of `React.createFactory`.

    > This helper is considered legacy, and we encourage you to either
    > use JSX or use `React.createElement()` directly instead.

References:
  https://facebook.github.io/react/docs/react-api.html#createfactory
  goatslacker/alt#283 (comment)
@vicky507
Copy link

vicky507 commented Mar 1, 2018

In my code i got uncaught type error which shows its not defined while i have bind it within constructor.
Pls help me

@aliaro428
Copy link

@troutowicz thanks

@zachowdhury
Copy link

zachowdhury commented Nov 6, 2018

React components using ES6 classes no longer autobind this to non React methods. In your constructor, add:

this.onChange = this.onChange.bind(this)

thanx to @troutowicz This solved my problem

@srihari906
Copy link

I am getting TypeError: Cannot read property 'name' of undefined, when the page loads.

I have registered onSubmit in the constructor
this.onSubmit = this.onSubmit.bind(this);

pls help me

@Anuskhan
Copy link

Use Arrow function . func =( )=>{ }

@nateeither
Copy link

React components using ES6 classes no longer autobind this to non React methods. In your constructor, add:

this.onChange = this.onChange.bind(this)

You saved my day

@sagaraideabits
Copy link

Thank you

@npacifique
Copy link

@troutowicz your response was very helpful, thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests