@kyanny's blog

My thoughts, my life. Views/opinions are my own.

recompose の withState

recompose の withState がわからなかったけどブログ記事とコードを読んだらなんとなくわかった(たぶん)。

公式の API ドキュメントのこのサンプルコードがわからなかった。

https://github.com/acdlite/recompose/blob/master/docs/API.md#withstate

const addCounting = compose(
  withState('counter', 'setCounter', 0),
  withHandlers({
    increment: ({ setCounter }) => () => setCounter(n => n + 1),
    decrement: ({ setCounter }) => () =>  setCounter(n => n - 1),
    reset: ({ setCounter }) => () => setCounter(0)
  })
)

withState の第二引数には stateUpdaterName を渡す。 次のステップの withHandlers の中で stateUpdaterName で名前を指定した関数、この例では setCounter が利用可能だが、 setCounter 関数自体は定義されてないのになんで利用できるの? setCounter 関数の実装はどうなってるの?というのが疑問だった。

その疑問が解決するきっかけはこのブログ記事にあった。

tech.ryukyu-i.co.jp

withStateを用いることでstateとそれを更新する為の関数を追加することができます。

props.msgはwithStateの内部のthis.stateであり、setMsgではsetStateが呼び出されているので、再レンダリングが可能です。

ここで、「もしかして setCounter って、 setState({ counter: }) 的なことをする関数で、 withState の内部で自動的に定義されるのか?」と思いついて、 withState の実装を読んだ。

https://github.com/acdlite/recompose/blob/eaa4dce9b762dc6516341330c49309412efcb58c/src/packages/recompose/withState.js#L19-L20

いろいろやってるけど、やはり setState している。なので先ほどの例でいうと setCounter は、要するにこういう関数として定義される。

function setCounter(updateFn) {
  var newStateValue = updateFn(currentStateValue);
  this.setState({
    'counter': newStateValue
  });
}

なので、 withHandlers の中で setCounter(function(currentValue) { return currentValue + 1 }) のような感じで使われることになり、最終的に setState される。

es2015 の arrow 関数の書き方がいまだにパッと理解できない。

https://github.com/acdlite/recompose/blob/eaa4dce9b762dc6516341330c49309412efcb58c/src/packages/recompose/withState.js#L21-L24

   ({ stateValue }) => ({
     stateValue:
       typeof updateFn === 'function' ? updateFn(stateValue) : updateFn,
   }),

これは、 babel で es5 文法に変換すると、こうなる。

'use strict';

(function (_ref) {
  var stateValue = _ref.stateValue;
  return {
    stateValue: typeof updateFn === 'function' ? updateFn(stateValue) : updateFn
  };
});

ともかく、 withState が何をするのかがなんとなくわかれば、仕事で読み書きする必要があるコードにはなんとか対応できそうなのでよかった。同じ要領で recompose の他の API も読み下せるだろう。


コールドリーディングをしていて他にも馴染みのない表記に出くわした。

https://github.com/acdlite/recompose/blob/eaa4dce9b762dc6516341330c49309412efcb58c/src/packages/recompose/withState.js#L31-L32

これも es2015 からの新しい文法で、オブジェクトのキーに変数を使うとき角括弧で囲うと変数展開してくれる。

qiita.com

JS Bin on jsbin.com