React v0.14のRC版が出たので紹介したいと思います。 http://facebook.github.io/react/blog/2015/09/10/react-v0.14-rc1.html
インストールはnpmからバージョン指定でインストールするかscriptを読み込むことで試すことが出来ます。
react-domが何なのかは後ほど説明します。
1 2 | |
or
1 2 3 | |
Major changes
ReactとReactDOMのパッケージが分割されました
react-nativeやreact-canvasなど、DOM以外の環境で使われるようになってくる中で、Reactのコアの部分とDOMに関わる部分がパッケージとして分割されるようになりました。
Reactのパッケージには、React.createElement、React.createClass、React.Component、React.PropTypes、React.Childrenが含まれています。
ReactDOMのパッケージには、ReactDOM.render、ReactDOM.unmountComponentAtNode、ReactDOM.findDOMNodが含まれています。
また、ReactDOMのパッケージにはreact-dom/serverとしてReactDOMServer.renderToStringとReactDOMServer.renderToStaticMarkupが含まれています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
scriptタグで読み込んで利用する場合は、ReactとReactDOMそれぞれを読み込んで利用する必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 | |
codemodも提供されているので既存のコードを一括で変換したい場合は使ってみるといいかもしれません。 https://github.com/facebook/react/blob/master/packages/react-codemod/README.md
Addons
また、Addonもそれぞれ個別のパッケージに分割されたので必要に応じてnpmでインストールするようになりました。
- react-addons-clone-with-props
- react-addons-create-fragment
- react-addons-css-transition-group
- react-addons-linked-state-mixin
- react-addons-perf
- react-addons-pure-render-mixin
- react-addons-shallow-compare
- react-addons-test-utils
- react-addons-transition-group
- react-addons-update
これによって、1つのAddonを使いたい時にその他全部のAddonがbundleされることがなくなりました。
scriptタグで読み込むためのreact-with-addonsのJSにはこれまで通り全てのAddonが含まれています。
また、batched_updatesとしてあったReactのイベントやライフサイクル以外でもバッチによる一括アップデートを行えるAddonはReactDOM.unstable_batchedUpdatesに移動しました。
1 2 3 4 5 6 | |
ちなみにunstable_batchedUpdatesという名前になっているけど今後どうする予定なのかを聞いたところ、全ての更新をバッチ更新にしたいということだったので最終的には不必要にしたいようです。
ReactとReactDOMやAddon のパッケージは意図しない挙動を避けるために同じバージョンを使うことが推奨されています。
DOMComponentに対するrefによる参照でDOM Nodeが取得出来るようになりました
これまでDOM nodeを取得したい場合にはReact.findDOMNode(this.refs.div) のようにする必要がありましたが、this.refs.divで直接DOM nodeを取得することが出来るようになりました。
findDOMNodeの呼び出しを書かなくてもいいというだけですが簡単になりました。
それと同時にrefでのComponentの参照はなるべくDOM Component以外では使わないようにしておかないと混乱を招きそうではあります。
また、ReactDOM.render(<div>foo</div>) とした場合の返り値もDOM Nodeになります。
ReactDOM.findDOMNodeは以降もComposite Componentに対するDOM nodeを取得する場合に利用することが出来ます。
Stateless Components
Propsだけに依存するような状態を持たないComponentを定義するための新しい方法が追加されました。
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
また、PropTypesやdefaultPropsも定義することが出来ます。
1 2 3 4 5 6 7 8 9 | |
あとContextも。
1 2 3 4 5 6 | |
v0.14では最低限の実装のみになっていますが、以降のバージョンではStateless Componentsで書いておくことでパフォーマンス最適化の恩恵が受けられるようになる予定です。 v0.14以降ではStateless ComponentsがComponent定義の第一の選択肢になっていきそうです。
react-toolsは廃止されました
これは以前にもブログで紹介されていましたが、react-toolsは非推奨になります(もう更新されない)。代わりにBabelを利用しましょう。
http://facebook.github.io/react/blog/2015/06/12/deprecating-jstransform-and-react-tools.html
- jsxコマンドは
babelコマンドになります。 - browserifyのtransformであるreactifyは
babelifyになります。 - webpackのjsx-loaderは
babel-loaderになります - Node.jsのサーバー上で動かすときに
require('node-jsx').install()としていたものはrequire('babel/register')になります。 - ブラウザでJSXを変換するために使うJSXTransformはbabel-core/browser.jsを読み込んでtypeを
text/babelにして使用します。
1 2 3 4 5 6 | |
ちなみにBabelは6.0でTransformが全て外出しになり使う場合はpluginとして読み込みようになることが予定されています。
1
| |
Babelによるコンパイル最適化が実施されるようになりました
Babel5.8.23以降のバージョンを利用することで、inlineElementsとconstantElementsを2つの最適化を行うことが出来るようになります。
これらは開発用のwarningやPropTypesによるチェックを無効化するので、productionモードの場合だけで有効にすることが推奨されています。
下記のコードを元に変換内容を確認してみます。
1 2 3 4 5 6 7 8 9 10 11 | |
最適化なし
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
inlineElements
inlineElementsの最適化を行うことでJSXの変換がReact.createElementへの変換ではなくてただのオブジェクトへの変換となります。
1
| |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
constantElements
constantElementsでは、変数の含まれていないReactElementに対する呼び出しをrenderの外に出すことで不必要なReact.createElementの呼び出しを避ける事が出来ます。
1
| |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | |
Breaking changes
ここでのBreaking changeはv0.13でwarningとして出力されていたものです。
- Propsは変更不可として扱われます。開発用のビルドでは
Object.freezeされています。Propsの値を変更したい場合は、React.cloneElementによって再生成する必要があります。 - childrenにオブジェクト形式で渡すことはサポートされなくなりました。配列に変更するか
react-addons-create-fragmentを使う必要があります。 classSetは削除されたので代わりにclassnamesのnpm packageを利用してください。
以下はv0.13でwarningが出力されていなかったものですが、簡単に修正することが出来る変更点です。
React.initializeTouchEventsは不要になったので削除してください。タッチイベントはデフォルトでサポートされるようになりました。- 前述したDOM Componentに対するrefの変更により、
TestUtils.findAllInRenderedTreeとそれに関連するhelperはComposite Componentのみを受け取るようになりました。(scryRendered〜、findRendered〜系のTestUtils)
Deprecations
getDOMNodeは非推奨になったので代わりにReactDOM.findDOMNodeを利用してください。前述したとおりDOM Componentの場合はReactDOM.findDOMNodeも不要です。setPropsとreplacePropsは非推奨になります。代わりに親のComponentから再度ReactDOM.renderを呼んでください。- ES6 ClassesによるComponent定義で
React.Componentを継承することが必須になりました。ES3 module patternはまだ使用することが出来ます。 styleのPropsを別のrenderと共有し変更することはPropsが変更不可として扱われる影響で非推奨となりました。react-addons-clone-with-propsは非推奨になりました。代わりにReact.cloneElementを使用してください。cloneElementはcloneWithPropsと違い、classNameとstyleのmergeは行いません。必要であれば開発者がmergeする必要があります。- 信頼性向上のために
react-addons-css-transition-groupがtransition eventをlistenしなくなりました。そのためtransitionEnterTimeout={500}のように明示的にdurationをPropsに指定する必要があります。
Enhancements
React.Children.toArrayが追加されました。ネストしたchildrenを受け取りkeyを設定したフラットな配列として返すことが出来ます。またReact.Children.mapもただの配列を返すようになりました。
1 2 3 4 5 6 7 8 | |
console.warnの代わりにconsole.errorでwarningを出力するようになりました(stack traceを出すため)。console.errorとして出力されるwarningは将来のバージョンで壊れるような使い方をしていた場合であり、must-fixなエラーとして扱われるべきです。可能であればReactDOMがXHTML互換なHTMLを生成するようになりました。
ReactDOMが
capture、challenge、inputMode、is、keyParams、keyType、minLength、summary、wrapといった標準の属性やautoSave、results、securityといった非標準な属性をサポートするようになりました。SVG属性のサポートが追加されました。
1
| |
imageのSVGタグがサポートされました。custome elementsで任意の属性がサポートされるようになりました。
audioとvideoタグに対するイベントのサポートが追加されました。
1 2 3 | |
shallowCompareのAddonがES6 ClassesのComponentでPureRenderMixnを使うためのマイグレーションのパスとして用意されました。CSSTransitionGroupがxxx-enter-activeのようにclassNameに追加する名前を任意に指定出来るようになりました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Helpful warnings
ReactDOMがHTML構造と不正な要素を受け取った時点でwarningを出力するようになり、更新時に突然エラーとして表面化するよりわかりやすくなりました。
document.bodyに対してReactDOM.render使用するとwarningを出力するようになりました。複数の異なるReactのオブジェクトを同時に利用しようとした場合に、warningを出力するようになりました。これはnpmとbrowserifyなどを組み合わせている場合に意図せずに起こってしまうことがあります。
Bug fixes
Mobile Browsersにおいてのクリックイベントのハンドリング(cursor: pointer周り?)にあったバグが修正されました。(特にMobile Safari)
SVG Elementが多くの場合で正しい名前空間と一緒に描画されるようになりました。
ReactDOMで複数のchildrenを持ったoptionの場合(
<select><option value={val}>{label}:{val}</option></select>)にエラーとなっていたバグが修正されました。サーバーサイドレンダリング時にselectタグのvalueがoptionタグのselectedとして反映されるようになりました。
同じdocumentに対して複数のReactのオブジェクトで要素を追加した状態になった時、イベントハンドリングのタイミングで発生していたエラーがなるべく起きないようになりました。但し、radio buttonを同じnameでrenderしていた場合などエラーになる状況は残っています。
小文字でないHTMLタグ名をReactDOMで使った場合でも問題にならないようになりました。ただしDOM Componentの場合には小文字で指定することを変わらずに推奨します。
ReactDOMが
animationIterationCount、boxOrdinalGroup、flexOrder、tabSize、stopOpacityのCSSプロパティに対して’px’を追加しないようになりました。react-addons-test-utilsでSimulate.mouseEnterとSimulate.mouseLeaveが利用可能になりました。react-addons-transition-groupで複数のnodeが同時に削除された場合にも正しく処理出来るようになりました。
ReactElement tags by Symbol
https://github.com/facebook/react/pull/4832
Reactではv0.14からReact.createElementでReactElementのインスタンスではなくてただのオブジェクトが返ってくるようになっていたり、上の方で紹介したBabelによるinlineElementsの最適化によってcreateElementの呼び出しがただのオブジェクトに変換されることからも分かる通り、オブジェクトをそのままVIRTUAL DOMとして扱いDOMを生成することが出来ます。
そのためユーザーによって作成されるオブジェクトをそのままrenderに渡していると意図しないコンテンツを表示されたりXSSのリスクがあります。
(ユーザーが任意のオブジェクトをそのままReactElementとして描画出来ること自体が問題ではありますが)
そのため、信頼されたReactElementかどうかを判別するための方法が議論されていました。セキュリティに興味のある人はこの辺りのissueを見てみると面白いと思います。
Reactでは最初はinstanceofでReactElementかどうかのチェックが行われていたのですが、それだと常にReactElementのインスタンスである必要がありオブジェクト化による最適化や複数のReactを使っていた場合にチェックが失敗するなど制限が多くなってしまいます。そのため、_isReactElementというがtrueかどうかをみるように変わりましたがこれでは信頼されたオブジェクトであるかを判定することは出来ません。
ユーザーが_isReactElementをオブジェクトに指定することでReactElementとして評価され、さらにReactにはdangerouslySetInnerHTMLというPropでHTMLをそのまま渡すことが出来るので…。
1 2 3 4 5 6 7 8 9 | |
v0.14ではSymbolを使って信頼されたReactElementかどうかを判定するようになります。
How it works?
1 2 | |
上記のようにSymbolを保持していおいて、それをReact.createElementで作成したObjectにも$$typeofというpropertyとして渡しておいて、ReactElementが有効であるかを返すisValidElementという関数の中の比較で利用しています。
Symbol.forは指定されたSymbolがあればそれを返しなければ作成して返すので、グローバルなSymbolとして扱うことが出来ます。これによってただのオブジェクトも複数のReactを使っていた場合もサポートすることが出来ます。
(複数のReactがある場合は既に書いた通り別途warningが出ます)
Symbolが実装されていないような環境だと固定の値(0xeac7)になるので、この機能を有効にしたい場合はSymbolのpolyfillを入れておく必要があります。
https://kangax.github.io/compat-table/es6/#Symbol
また、BabelのinlineElementsの最適化を使った場合にどうなるんだと思った人もいると思いますがすでに対応されて5.8.24としてリリースにされています。
https://github.com/babel/babel/pull/2352
v0.15?
v0.15はGarbage collection releaseと位置づけられていて、つまりAPIの整理などに重点が置かれたリリースになる予定でv0.14のリリースから遠くないタイミングで出るそうです。