お前は何を言っているんだみたいなタイトルですが、つまり・・。
// 子 const SFC = ({ some, vars, and, handler, }) => { return ( <div onClick={handler}></div> ); } // 親 class Container extends React.Component { render() { // 略 <SFC {...item} handler={this.handler} /> } handler(ev) { // ココで子に渡したpropsを使ってなんかしたい } }
さてどうしたらいいんだという話。
jsx-no-bindとは
eslint-plugin-react/jsx-no-bind.md at master · yannickcr/eslint-plugin-react · GitHub
eslint-plugin-reactのルールのひとつで、JSXの中で関数書くな!というやつ。
このルールがなければ↓こんな風に書けるので何も困らない。
// SFC <div onClick={(ev) => { handler(ev, vars); }}</div>
けど、レンダリングする度にFunctionがスコープを作ってパフォーマンスが云々・・というわけで、せっかくSFC使っておきながらなんか中途半端に甘えを許すみたいな気持ちになる。
できればこのルールはstrictにtrueなまま運用したいなーと。
でも`props`渡せないし困るしうーむ。
さて。
案1: 懐かしいdata属性
上位のハンドラで`ev`は取れるなら、そこを経由すればいいのでは作戦。
// SFC <div onClick={handler} data-vars={vars}></div>
こうしちゃえば、
// 親 handler(ev) { // 取れる! const vars = ev.currentTarget.getAttribute('data-vars'); }
ただしこれだと文字列しか渡せないので、たぶん後々に困るケースがありそう・・。
案2: jsx-no-bindをあきらめる
jsx-no-bindにはオプションが指定できて、`allowArrowFunctions`ってのがある。
要するに、アローファンクションなら使ってもいいよっていうものなので、これを`true`にすれば最初の例でも怒られない。
いやでもこれはーなんというかー!
案3: SFCをあきらめる
SFCをやめて、普通にCompomentにすればいける。
// 元SFC class C extends React.Component { constructor() { super(); this._handler = this._handler.bind(this); } render() { return ( <div onClick={this._handler}></div> ); } _handler(ev) { const { vars, handler } = this.props; handler(ev, vars); } }
いやでもそうなると今度は`prefer-stateless-function`というルールがですね・・。
eslint-plugin-react/prefer-stateless-function.md at master · yannickcr/eslint-plugin-react · GitHub
案4: JSXの外でbindする
それで最終的に思いついたのがコレ。
// SFC const SFC = ({ some, vars, and, handler, }) => { // ここならJSXの外なので怒られない const _handler = (ev) => { handler(ev, vars); }; return ( <div onClick={_handler}></div> ); }
これだー!!
と思ったけど、これはパフォーマンス的にはいいのか?JSXの中でスコープ作るのと何が違うんやろう?という疑問がわきまして。
どうするのが最良か、誰かおしえてくれんかなーということで、記事にしてみました。
案5: コンポーネントの外でbindする( by @yosuke_furukawa
関数を返すハンドラを渡して、動的にやるパターン。
// SFC const SFC = ({ some, vars, and, handler, }) => { return ( <div onClick={handler(vars)}></div> ); } // 親 handler(vars) { return (ev) => { vars; // 取れる! }; }
なるほど!天才!って最初は思ったけど、生成後のコードという意味ではあまり変わらんので、書き味の好みでお選びくださいって感じです。
他のハンドラと並べて見た時に、親でなんでコレだけ関数返してるんやろう・・って気持ちになる人もいるかもしれない!
ちなみにビルドすると
前後は省略してるけど、違いはコレだけ。
// 案2 return React.createElement( 'div', { onClick: function handler(ev) { _handler(ev, vars); } }, // 案4 var _handler = function _handler(ev) { handler(ev, vars); }; return React.createElement( 'div', { onClick: _handler }
`React.createElement()`にどう関数が渡るかだけの違いで、これだけ見るとなんも変わらんよね。
というわけで結論
今のところコレだ!!というパターンはないっぽいので、お好きなやつを使う。
@leader22 @yosuke_furukawa ShouldComponentUpdateとかPureComponentを使う時に注意する意味あいの方が大きいかな。ただ避けられるなら避けた方がいいので、まぁプラクティスとして設定しておくのはいいと思う。
— Toru Kobayashi (@koba04) 2016年9月8日
まさかのオチ
@leader22 @yosuke_furukawa ちなみに https://t.co/szBxRTF5IH
— Toru Kobayashi (@koba04) 2016年9月8日