Recompose
RecomposeはHigher-order Componentsをサポートするライブラリ。
Higher-order Componentsについては下記記事で軽くまとめた。
どんなライブラリ?
- HoCsを作成・提供するための便利関数ライブラリ
- 「lodash的なノリで、関数群をまとめている」とのこと
- 作者はflummoxやreact-actionなど、reactやredux関連を多く作っているライブラリの作者。
- まだ 0.20で微妙にAPIは安定してない部分もアリ
まずはサンプル
例: 未サポートブラウザの時にメッセージ出す
説明だけだとわかりづらいので、個人的に一番とっつきやすかったbranch
を使って、特定のブラウザの場合に「お使いのブラウザはサポートされてません」と出すサンプルを書いてみる。
普通のReact.Component
で書く(Recomposeナシ)
export const NotSupportedMessage = () => <h3>お使いのブラウザはサポートされておりません</h3>
export default class MainApp extends Component{
isSupportedPlatform(){
if(/*ブラウザが未サポートかの判定*/){
return false
}
return true
}
render() {
if(!this.isSupportedPlatform()){
return <NotSupportedMessage />
}
return (
<div className="SomeApp">
何らかのアプリケーション
</div>
)
}
}
まあこれでも全然問題ない。が、本筋のSomeApp
の部分までスッとたどり着いていないし、このあたりの処理が肥大化すると色々辛いことになりそうなのが見える。
Higher-order Componentで書く(Recomposeアリ)
import branch from 'recompose/branch'
import renderComponent from 'recompose/renderComponent'
// branchは、下記のように引数を取る
// branch(判定関数, trueの時, falseの時)
const NotSupportedMessage = () => <h3>お使いのブラウザはサポートされておりません</h3>
const SomeMyApp = () => (
<div className="SomeApp">
何らかのアプリケーション
</div>
)
const isSupportedBrowser = () => {
if(/*ブラウザが未サポートかの判定*/){
return false
}
return true
}
const withBrowserCheck = branch(
isSupportedBrowser,
component => component, // trueの時は、受け取っていた引数をそのまま流用
renderComponent(NotSupportedMessage)
)
const MainApp = withBrowserCheck(SomeMyApp)
withBrowserCheck
がHigerOrderCoponentとして、ReactComponent
を渡すと、ブラウザチェックを挟んだ状態のSomeMyApp
をReactComponent
として返してくれるようになる。
また、もし「desktopだけの判定もいれたい」とかになったら、下記のような感じで拡張されるので、本筋のSomeMyApp
の肥大化が防げる
const MainApp = compose(withBrowserCheck, withDeviceCheck)(SomeMyApp)
Recomposeが提供してる関数の種類など
だいたいこんなあたりがある。
-
-
withState()
,withContext()
,withReducer()
,shouldUpdate()
など - stateやらcontextを利用したり。
-
withReudcer()
は、ReduxやFlux Utilなどから影響受けている感じ。
-
-
Propsを色々うまいことする系
-
mapProps()
,withProps()
,defaultProps()
,flattenProp()
, など -
branch
の次に扱いやすそうだなと思った分類。 -
withProps
は<Some hoge={fuga} />
をwithProps({hoge: fuga})(Some)
とかに出来る。 -
defaultProps
とうまく組み合わせると結構良い。
-
-
Lifecycle扱う系
-
shouldUpdate()
、lifecycle -
Stateless Functional
でもReact.Component
でのライフライクルを扱えるようになる。 -
shouldUpdate
は、第一引数としてtest関数を渡すので、スマートに書けそう
-
-
-
componentFromStream()
,mapPropsStream()
,createEventHandler()
,setObservableConfig()
- 元々、
rx-recompose
として別ライブラリでpublishされていたが、最近のバージョンアップで統合した。 -
RxJS
だけでなく、most
、kefir
、Bacon
、xstream
など、だいたい一通りのStreamライブラリ使えるっぽい
-
-
-
setStatic()
,setPropTypes()
,setDisplayName()
-
propTypes
やdisplayName
などComponentにstaticに与えられるプロパティを与える。
-
-
Renderをいい感じにする系
-
branch()
,renderComponent()
,renderNothing()
- Sampleで触れたので省略
-
-
-
componentFromProp()
, - READMEのサンプルにある。
- ぶっちゃけあんまりまだちゃんと理解出来てない
-
-
-
onlyUpdateForKeys()
,onlyUpdateForPropTypes()
など - READMEのサンプルにある。
- updateする対象を絞ったりしてパフォーマンス調整に役立たせられる
-
まとめ
雑感・良かった所
-
Stateless Function
を推してる感じがする。 - HoCsの下記の利点が活かしやすい
- "smart" vs "dumb" component patternにのっとりやすい
- Component巨大化を押さえやすい
- HoCsに対するテストしやすい
- 再利用性を高くしやすい
- いわゆるテンプレート的なviewとロジックをどんどん分離出来る感覚がとても良い
-
withProps
あたりをうまく扱えると、Component
が素のtemplateっぽくなっていって良い
-
- jsxの記述が減らしやすい
- テンプレート的な扱いをするComponent以外だとほとんどjsxいらないとすら言えそう
- HoCsは簡単に自前実装出来るが、ちょっとだけ自前より嬉しい事が多い。
- いい感じにHoCsの名前をつけてくれたりするので、デバッグに役立つ
-
compose
など、自前だと微妙に面倒な部分を提供してくれる
良くなかった所、注意点
- HoCsに慣れるまでちょっとつらい。
- やりすぎると可読性酷くなりかねない
- jsxの記述量減っても、全体のコード量増えそう
- 一周回って「あれ、これjsxの方が簡素に書けてね?」みたいな事がたまにある