とっしぃのTech Memo

PHPとかサーバとか他色々言語のメモ的な。あとはたまにガジェットとか。

ES6でReact使ってたらsetStateがundefinedとか怒られた件

急に寒くなってきたこの頃、いかがお過ごしでしょうか。

鼻水やらくしゃみやら頭痛やら止まらなくて調べたら「寒暖差アレルギー」なんじゃないかと思い始めました。

とっしぃです。

Uncaught TypeError: Cannot read property 'setState' of undefined

ところで、業務に関係ありそうでなさそうな適当なツールChromeのextensionで作ってみようと思い、 どうせ外に出すわけでもないツールだし以前から興味のあったReactで書いていたわけです。

更にどうせならES6で書かない理由もないということで、

var CommentBox = React.createClass({
...

ではなく

class CommentBox extends React.Component {
...

って感じ。

でもそこで

class CommentBox extends React.Component {
    
    constructor(props) {
        super(props);
        let data = localStorage.getItem('data_key');
        this.state = {
            data: data
        }
    }

    changeData(e) {
        this.setState({data: e.target.value});
    }

    save(e) {
        e.preventDefault();
        localStorage.setItem('data_key', this.state.data);
        return false;
    }

    render() {
        <form>
            <Input type="text" value={this.state.data} onChange={this.changeData} label="DATA" />
            <button onClick={this.save}>SAVE</button>
        </form>
    }
}

的に書いてみたところ、developer toolのコンソールに

Uncaught TypeError: Cannot read property 'setState' of undefined

とか出てるじゃないですか。

色んなチュートリアル見ながらその通りやったのに(´・ω・`)

調べてみると

qiita.com

facebook.github.io

どうやら

var CommentBox = React.createClass({

で書いた場合はthisが勝手にbindされるけど、ES6で

class CommentBox extends React.Component {

って書いた場合はthisがbindされないとのこと。

なのでコンストラクタで明示的に

class CommentBox extends React.Component {
    constructor(props) {
        super(props);
        let data = localStorage.getItem('data_key');
        this.state = {
            data: data
        }

        this.changeData = this.changeData.bind(this);
        this.save = this.save.bind(this);
    }

とbindしてあげないといけないらしい。

まとめ

Reactもbabelもちょこちょこバージョン上がってるので npm install して落ちてきたバージョンが新し目だったらちゃんとリリースノート(の翻訳でもいいので)を見といた方がいいですね。 ReactなんてrenderメソッドがReactクラスじゃなくてReactDOMクラスのメソッドになってたし。