React.js with ES6 で要素のフォーカスが当たった・外れたでクラス着脱させる

1つのイベントハンドラで出来ないかなと思ったんだけれど、どうも「フォーカスが当たった = onFocus」、「フォーカスが外れた = onBlur」 とそれぞれのイベントハンドラで拾ってあげなきゃいけなさそう。
React で定義できるイベントハンドラはドキュメント参照。

facebook.github.io

というわけでその2つを要素に定義して、自分なりに実装してみた。

onFocus/onBlur で異なるメソッド呼び出してみる

_focusInputSeachKeyword() {
    this.setState({ isFocusInputSeachKeyword: true });
}

_blurInputSearchKeyword() {
    this.setState({ isFocusInputSeachKeyword: false });
}

render() {
    // 真偽値を見てフォーカス時のクラスを付けるか否かを決定する
    const spanSearchIcon = this.state.isFocusInputSeachKeyword ? <span className='fa fa-search is-focus'></span>
                                                               : <span className='fa fa-search'></span>;
    return (
        <li className='md-li-comment-search'>
            <input type='text'
                   className='md-keyword-search-comment'
                   placeholder='input search keyword'
                   onChange={this._searchIncremental.bind(this)}
                   onFocus ={this._focusInputSeachKeyword.bind(this)}
                   onBlur  ={this._blurInputSearchKeyword.bind(this)} />
            {spanSearchIcon}
        </li>
    );
}

onFocus / onBlur でそれぞれ異なるメソッドを呼び出し、同じ state に対して異なる真偽値を与えてみた。冗長さがある印象。 renderreturn 前でわざわざ変数に切り出さずその中でやればいいんでない? という意見も聞こえそうだけれど、プログラマチックなことを構造内に書くのは避けたい考えがあって、僕の場合はこういう書き方を好んで選んでいる。 といいつつ1ライナーループくらいなら中に書くこともあるけれど。

イベントハンドラから引数を渡して同じ関数を呼び出してみる

昼食のために建物から出て外を歩き出した瞬間こうすればいいことに気がついた。PC 画面にらめっこやめて歩くの大事。

_changeIsFocusInputSearchKeyword(isFocus, e) {
    this.setState({ isFocusInputSeachKeyword: isFocus });
}

render() {
    // 真偽値を見てフォーカス時のクラスを付けるか否かを決定する
    const spanSearchIcon = this.state.isFocusInputSeachKeyword ? <span className='fa fa-search is-focus'></span>
                                                               : <span className='fa fa-search'></span>;
    return (
        <li className='md-li-comment-search'>
            <input type='text'
                   className='md-keyword-search-comment'
                   placeholder='input search keyword'
                   onChange={this._searchIncremental.bind(this)}
                   onFocus ={this._changeIsFocusInputSearchKeyword.bind(this, true)}
                   onBlur  ={this._changeIsFocusInputSearchKeyword.bind(this, false)} />
            {spanSearchIcon}
        </li>
    );
}

onFocus / onBlur が呼び出すメソッドが1つになり、冗長さも削ぎ落とせた。 いずれにしても spanSearchIcon に渡す値が span まるごとなのどーなの…感は否めない。 ついでに ES6 で記述する React の宿命なのだが、もともと bind(this) で this の拘束をしているので、受け取るメソッドでは第1引数が指定した引数、第2引数がイベントオブジェクトになるのは、なんだか直感的ではない。

余談というか結論

ここまで書き終わってから見つけたもの。

github.com

これを使うべきだった。