2017Reactのv16がリリースされたので、変更点などを整理したいと思います。Fiberについては、下記で書いたりもしているのでそちらも参考にしてみてください。FiberReactはなぜFiberで書き直されたのか?Reactの課題と将来像を探る新機能render関数から文字列や配列を直接返せるように地味に嬉しい機能ですね。これまでは無駄にspanやdivで囲むしかなかったのが、直接文字列や配列を返すことができるようになります。/></Row>配列を返す場合は、keyを必ずつける必要があります。それをJSXのSyntaxレベルでサポートするという議論もあったりします。Boundaries子のComponentのrender関数やライフサイクルメソッドで起きたエラーを、componentDidCatchというライフサイクルメソッドでキャッチできるようになります。これによって、エラーが起きたことをユーザーに伝えたり、エラーリポートのサービスに送信できるようになります。}}上記のように、componentDidCatchの引数には、Errorオブジェクト以外にinfoというオブジェクトを受け取ります。infoは今のところcomponentStackのプロパティしか持っていません。componentStackには、Compnentのスタックトレースが文字列で入っています。したがって、これをエラーと一緒に送信すると、どこのComponentでどのエラーが発生したのかがわかります。Boundariesの対象になるのは、render関数とライフサイクルメソッドの中のエラーだけです。Requestなど)で起きたエラーは対象になりません。Boundariesの対象となるエラーに対する扱いが変更されています。v15までは、エラーが発生したらそこで処理が中断されていました。したがって、途中のComponentのrenderで処理が止まるなど、不整合なViewをユーザーに見せてしまう可能性がありました。Containerから全てアンマウント(DOMから削除)されるようになります。それを避けたい場合には、上記の例のようにcomponentDidCatchを定義してsetStateするなどしてエラー用の表示を行う必要があります。親のComponentでcomponentDidCatchを定義したり、componentDidCatchを定義したComponentでアプリケーション全体のComponentをラップしておくと安心かと思います。PortalsReactDOM.createPortalというAPIが追加されました。https://facebook.github.io/react/docs/portals.htmlこれは、Componentツリーの外側に対するrenderをComponentツリーの一部として扱えるようにする機能です。文字だけで書くとわかりにくいので例として、どこかアプリケーションの外側にモーダル用のDOMがあって、アプリケーションのStateによってモーダルを表示したい場合を考えてみます。}}というように、render関数の中に書くことが出来ます。この場合Modalは、Contentsの隣に配置されたComponentと同様に処理されます。</div></section>とあった場合、<p>Portal</p>をクリックした場合にも、cosole.log('click')が呼ばれます。Renderingサーバーサイドレンダリングは完全にリライトされました(既存の実装をベースに)。これまでは、クライアントでのDOM構築と同じ流れでHTMLを構築していたのですが、下記の1ファイルに切り離されました。https://github.com/facebook/react/blob/master/src/renderers/shared/server/ReactPartialRenderer.jsこれにより、無駄な処理が減ったことによる高速化やStreamサポートが簡単に行えるようになりました。独立したファイルになったことで、今後のパフォーマンスチューニングもやりやすくなったと思います。Stream対応のAPIの追加とHydarationの方法の変更です。Streamの対応については、renderToNodeStreamとrenderToStaticNodeStreamのAPIが追加されたので、それを使うだけです。Stream!</p></div>Hydrationの方法の変更については、クライアント側の変更とバリデーションロジックの変更があります。ここでいうHydrationとは、サーバーサイドレンダリングで返したHTMLが生成したDOM要素を、クライアント側でのレンダリング時に再利用することを指します。クライアント側でのAPIの変更については、ReactDOM.renderの代わりにReactDOM.hydrateという専用のAPIを使うようになります。v16の段階では、ReactDOM.renderによるHydrationもサポートされますが、将来的に廃止される予定です。ちなみに、renderToNodeStreamとrenderToStaticNodeStreamによる出力の違いは、Rootの要素にdata-reactrootがあるかないかの違いだけです。このdata-reactrootはReactDOM.renderでHydrationするかどうかの判定に使われているだけです。将来的にはどちらか1つのAPIだけになると思います。ReactDOM.hydrateを使う場合は、renderToStaticNodeStreamで生成したHTMLに対してもHydration出来ます。[2017/10/01:訂正]renderToNodeStreamとrenderToStaticNodeStreamによる出力の違いは、Rootの要素にdata-reactroot以外にも、変数部分を識別するためのコメントノードの差し込みがあります。したがって、Hydrationする場合にはrenderToNodeStreamを、それ以外の場合はrenderToStaticNodeStreamという使い分けになります。Hydrationの方法については、v15まではrenderToStringで生成したHTMLのdata-react-check-sumという属性につけられたチェックサムを使い、クライアント側で生成したReactElementの構造が一致するかどうか判定し、一致すればDOMを再利用して一致しなければDOMを再構築する方法を採用していました。v16では、サーバーサイドレンダリングで構築したDOMを、React.hydrateの際に可能な限り再利用しようとします。ReactElementの構造が一致するかどうかの確認が、ReactElementの単位で行われるようになります。バリデーションするというよりも可能な限り再利用する方針であるため、サーバーサイドレンダリングした内容とのdiff次第では、意図しない結果となる場合があります。https://github.com/facebook/react/issues/10591サーバーサイドレンダリングで意図的に異なるコンテンツを返している場合は、一度DOMをリセットする方がいいかもしれません。これにより、data-react-check-sumだけでなく、react-textのコメントやdata-react-idもHTMLに付加されなりました。サーバーサイドレンダリングについては、補足記事書きました。Attributesこれまでは、ホワイトリストで管理された属性以外は、warningを出しつつDOMには反映されなかったのですが、v16からは反映されるようになります。これにより、ng-xxとかv-xxみたいな属性や、一部ブラウザーが実装しているけどまだ標準化されていないような属性値も使えるようになります。on〜といった属性値については、セキュリティ的なリスクから反映されません。属性が期待している型とは異なる値を渡した場合に、値が反映されなくなります。classNameにfalseを渡した場合は、v15までは”false”という文字列がクラス名と設定されていましたが、v16からはwarningが出て反映されなくなります。詳細は、下のブログに。SizeBrowserifyを使ったビルドからRollupを使ったビルドに変更されて、フラットバンドルになりました。Rollupを使って1つのモジュールとしてビルドすることで、Browserifyが付加する依存関係解決のためのコードが不要になります。その結果、ファイルサイズの削減やブラウザー上での初回読み込みの時間が短縮されます。reactとreact-domのv16をnpmからインストールすると、下記のような構造になっており、内部モジュールの構造は維持されていません。unstable-native-dependencies.js上記のcjsがcommonJSのビルドが入っているディレクトリです。〜.development.jsと〜.production.min.jsがあるのは本番用のビルドと開発用のビルドを分けるためです。この分岐はindex.jsの中でprocess.env.NODE_ENVによって行われています。importと言われているreact/lib/xxxのような形での内部モジュール参照が出来なくなります。これは、主にカスタムレンダラーの実装や内部の挙動を変更させるために行われており、そういったライブラリーを使っている場合には注意が必要です。ちなみに、下記をwebpackとBabel(es2015とreactのprest)でビルドして、比較してみるとこんな感じでした。buildは小さくなってますね。UMDビルドのディレクトリ名とファイル名が変更になっているので、CDNから利用する場合などは注意してください。PATENTSからMITになりました。https://code.facebook.com/posts/300798627056246/relicensing-react-jest-flow-and-immutable-js/Addonsv15.5の時点で、廃止するアナウンスが出ていましたが、react-addons-xxxのパッケージは廃止になります。基本的には、別パッケージになったりしているので使っているものがあれば下記で移行パスを確認してみてください。https://facebook.github.io/react/blog/2017/04/07/react-v15.5.0.html#discontinuing-support-for-react-addonsreact-addons-perfに関しては、?react_perfをURLにつけてBrowserのPerformanceのTimelineで計測する方法になります。https://facebook.github.io/react/docs/optimizing-performance.html#profiling-components-with-the-chrome-performance-tabreact-with-addons.jsのようなUMDビルドももう提供されません。Fiberに実装が変わったことによる、処理順の変更などが多いです。ReactDOM.renderとReactDOM.unstable_renderIntoContainerをライフサイクルメソッドの中で読んだ場合にはnullが返るようになります。setStateでnullを渡した場合、更新処理が行われなくなります。renderの中でのsetStateは常に更新処理が行われるようになります(以前はされない場合があったらしい)。そもそもrenderの中でsetStateを呼び出すべきではないですが。setStateの第2引数のコールバックはcomponentDidMountとcomponentDidUpdateの後すぐに呼び出されるようになります。以前は全てのComponentがrenderされた後に呼び出されていました。/>に置き換えたとき、B.componentWillMountが常にA.componentWillUnmountの前に呼ばれるようになります。以前は、refを更新する際のデタッチ(nullでの呼び出し)はComponentのrender関数の前に呼ばれていましたが、render関数の後に変更になります。React以外によって、編集されたDOMに対して再度ReactDOM.renderを行った時にwarningが出るようになりました。この場合は一度ReactDOM.unmountComponentAtNodeでアンマウントしてから再度renderを行います。componentDidUpdateのライフサイクルメソッドが第3引数としてprevContextを受け取らなくなりました。ShallowRendererにunstable_batchedUpdatesはもう実装されません。下記はすでにwarningの対象で今回のバージョンで完全に削除されたものです。React.createClassが削除されました。代わりにcreate-react-classを使います。React.PropTypesが削除されました。代わりにpro-typesを使います。React.DOM.xxxが削除されました。代わりにreact-dom-factoriesを使います。Requirements動作環境として、MapとSetとrequestAnimationFrameが必要になりました。必要に応じてpolyfillを設定します。Fiberについてはすでに書いたので省略しますが、v16の時点ではv15と互換性のある同期モードで動作します。したがって、v16にあげたからといって、大きくパフォーマンスが向上したりするようなことはありません(多少のパフォーマンスが上がるかもですが)。現時点では、いくつかの方法を使うことで、非同期renderingを試すことができるので紹介します。非同期rendering周りはまだ安定しておらず、コードもガンガン変わっているので注意が必要です。Priorityとして扱われて、requestIdleCallbackを使って非同期に処理されます。Priorityとして扱われるようになります。Componentとして使う方法と、PureComponentのようにextends対象として使う方法があります。{}ReactDOM.flushSyncReactDOM.flushSyncで囲んだ中での更新処理は、同期(Sync)のPriorityとして扱われます。v16ではデフォルトが同期のPriorityなので、効果ありませんが、上記のunstableなAPIの中で同期的な更新を行いたい場合に、使用します。newState);});あとは、今後の非同期renderingに備えて、既存のStateの値を元に更新処理を行う場合は、第1引数に関数を渡す方法でのsetState呼び出しをするようにしておいた方がいいと思います。Fiberでは、柔軟なスケジューリングを可能にすることで、UIのレスポンス性を向上させることが目的です。Rendererを実装するためのパッケージはv16には間に合いませんでしたが、下記のPRで作業中なので、気になる人はwatchしておくといいと思います。Rendererに便利なAPIが追加されて使いやすくなりました。Rendererはツリー全体をrenderします。下記のようにfind〜やfindAll〜のAPIが追加されており、インスタンスにもアクセスできるため、setStateを呼び出したりもできます。Fiberが提供する機能を利用できます。2);後、DOMComponentのrefに対するMockの挙動を定義することもできます。Rendererのドキュメントを書いてみたので、そちらも参照してみてください。https://facebook.github.io/react/docs/test-renderer.html英語ですがブログも書いたのでそっちも。https://medium.com/@koba04/testing-react-components-with-react-test-renderer-b4df590d0320Enzymeenzymeも同じタイミングでv3がリリースされました。v3からはAdapterのアーキテクチャになっており、対象とするReactのバージョンに応じたAdapterをインストールして設定します。});上記をNodeやMochaの--requireオプションに設定したり、JestのsetupFilesに定義すれば毎回書く必要はありません。これにより、今後はpreactのアプリケーションもサポートできるようになるかもしれません。