1

EDIT: My mistake, my webpack hotloader was caching the old js for some reason every time I ran a build. Reset and rebuilt and it seems to be working now.

I'm trying to create a simple searchbox using es6 style class declaration in a yahoo fluxible react app. I'm working off the todo example, converting it to es6 style syntax and I'm getting an error on this.setState in the _onChange method. I've bound the functions to "this" in the constructor but I'm still getting the error.

import React from 'react';
import searchProducts from '../actions/searchProducts';

const ENTER_KEY_CODE = 13;

class SearchBox extends React.Component {

    static contextTypes = {
        executeAction: React.PropTypes.func.isRequired
    };

    static propTypes = {
        text: React.PropTypes.string
    };

    static defaultProps = {
        text:''
    };

    constructor(props) {
        super(props);
        this.state = {
            text: props.text
        };
        this._onChange = this._onChange.bind(this);
        this._onKeyDown = this._onKeyDown.bind(this);
    }

    render() {
        return (
            <input
                className="search-box"
                name="search-keyword"
                value={this.state.text}
                onChange={this._onChange}
                onKeyDown={this._onKeyDown}
            />
        );
    }

    _onChange(event, value) {
        console.log( event.target.value);

        //error is here///////////////////////////////////////////////////
        this.setState({text: event.target.value}); 
    }

    _onKeyDown(event) {
        if (event.keyCode === ENTER_KEY_CODE) {
            event.preventDefault();
            event.stopPropagation();

            var text = this.state.text.trim();
            if (text) {
                this.context.executeAction(searchProducts, {
                    text: text
                });
            }
            this.setState({text: ''});
        }
    }

}


export default SearchBox;
MonkeyBonkey
  • 46,433
  • 78
  • 254
  • 460
  • in `_onKeyDown` also there is error with `setState`? or error only in `_onChange`? I simplified you version https://jsfiddle.net/69z2wepo/19646/ and code works fine with same approach., and your code https://jsfiddle.net/69z2wepo/19649/ also works fine – Oleksandr T. Nov 01 '15 at 14:25
  • could you post error message? – Oleksandr T. Nov 01 '15 at 14:46
  • the error message is "setState on undefined" since it thinks that "this" is undefined on "this.setState" – MonkeyBonkey Nov 01 '15 at 14:52
  • @Alexander I tried the jsfiddle and it seems to work with my code as well... when it's outside the fluxible framework.. https://jsfiddle.net/8cyum94g/ I wonder if there is something about the way fluxible loads the components that's making it not work? I' added the searchbox to the boilerplate fluxible starter yeoman template. – MonkeyBonkey Nov 01 '15 at 15:00
  • Ok it seems to work now - it was an error with the webpack hotloading, for some reason it kept caching the old js in the generated code – MonkeyBonkey Nov 01 '15 at 15:07

2 Answers2

0

Edit: Disregard. I completely missed the part of the constructor where you bound the methods. Hmm.. What does the error message say exactly?

Have a look at section three of this article about refactoring react components to es6 classes.

When using the React.createClass({componentObjectLiteral}) syntax, React binds your object methods to the component instance, so that when your _onChange method gets called as your input's onChange callback function, the this keyword in your _onChange method is bound to your component.

React does not auto-bind your methods for you, so you have to do it yourself. Change your JSX to onChange={this._onChange.bind(this)}

psigns
  • 179
  • 2
  • 4
  • Isn't that what the binding in the constructor is doing already? In either case - tried changing the syntax on the jsx but still getting the same error – MonkeyBonkey Nov 01 '15 at 13:48
  • hmm either way it's still getting the same error even with that change.. and most of the code is boilerplate copied verbatim from the react fluxible sample todo app. Not sure what magic react does with the bindings in the jsx either.. – MonkeyBonkey Nov 01 '15 at 14:18
0

psigns is correct React.createClass() automatically binds the methods to the component instance for you. This is not the case when you use the class syntax in React.

But there is a very neat possibility when you combine property initializers with arrow functions:

class SearchBox extends React.Component {

  // …

 _onChange = (event, value) => {
    // …

    // this will be bound to component
    this.setState({text: event.target.value}); 
  }

  // …

}

Then you can use the method like you did before in the jsx part:

onChange={this._onChange}  // without .bind(this)

I learned this from reading Steven Luscher's excellent post.

cutemachine
  • 5,520
  • 2
  • 33
  • 30