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 関数の実装はどうなってるの?というのが疑問だった。
その疑問が解決するきっかけはこのブログ記事にあった。
withStateを用いることでstateとそれを更新する為の関数を追加することができます。
props.msgはwithStateの内部のthis.stateであり、setMsgではsetStateが呼び出されているので、再レンダリングが可能です。
ここで、「もしかして setCounter って、 setState({ counter: }) 的なことをする関数で、 withState の内部で自動的に定義されるのか?」と思いついて、 withState の実装を読んだ。
いろいろやってるけど、やはり setState している。なので先ほどの例でいうと setCounter は、要するにこういう関数として定義される。
function setCounter(updateFn) { var newStateValue = updateFn(currentStateValue); this.setState({ 'counter': newStateValue }); }
なので、 withHandlers の中で setCounter(function(currentValue) { return currentValue + 1 }) のような感じで使われることになり、最終的に setState される。
es2015 の arrow 関数の書き方がいまだにパッと理解できない。
({ 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 も読み下せるだろう。
コールドリーディングをしていて他にも馴染みのない表記に出くわした。
これも es2015 からの新しい文法で、オブジェクトのキーに変数を使うとき角括弧で囲うと変数展開してくれる。