blog.koba04.comkoba04's twitter accountkoba04's GitHub account

React v15.5(6) and v16

2017/04/14 @koba04

Reactのv15.5がリリースされたので、v15.5での変更点とv16についてのまとめです。

v15.5はバグフィックスとv16での変更点に対する準備なので、可能ならあげておいた方がスムーズにv16がリリースされた時に対応できると思います。

基本的には、v16で色々と廃止するための警告が主になります。 最近のバージョンと同様に、コアから必要なもの以外をどんどん削ぎ落としていく流れです。

この警告に対応するために、Enzymeなどでは利用するために必要なライブラリーが変更されているので更新する際には注意が必要です。

また、当初の予定ではv15.5がv15系の最後のリリースになる予定でしたが、上記のような混乱もあったためフォローアップとしてv15.6もリリースされることになりました。 なので、v15.6がリリースされてから対応するのもアリだと思います。

廃止されるものは色々ありますが、基本的に全てのものに対してマイグレーションのパスは提供されているので対応可能だと思います。 ただ、アクティブにメンテされていないくて15.5対応版をリリースしていないライブラリーを使っていると色々警告が出ると思います。 場合によっては、その警告によってテストが壊れることがあるかもしれません。

Deprecated React.createClass

廃止されること自体は前から言われていたので、使わないようにしていた人も多いと思いますが、create-react-classとして別パッケージとなり、v16ではreactから削除されます。

import createReactClass from 'create-react-class';

そのためv15.5では、React.createClassを使おうとすると警告が出ます。

自分の書いたコードでReact.createClassを使っている場合は、React.Componentを使ったComponent定義かStateless Functional Componentsに書き換える必要があります。

mixinを使っているなど、どうしてもReact.createClassを使いたい場合はcreate-react-classを使うこともできますが、可能な限りReact本体が提供する方法を利用する方がいいと思います。

React.createClassからReact.Componentの定義に書き換えるcodemodも提供されているので、使ってみるのもいいかもしれません。

このcodemodでは、React.createClassが提供するautobindを実現するために、property initializerのシンタックスを利用します。そのため、変換後はbabel-plugin-transform-class-propertiesを使用する必要があります。(Stage 2)

v16になった時点でReact.createClassを使っているライブラリーを利用している場合には、PR送って対応してもらうか、React.createClasscreate-react-classを代入するなどの対応が必要になるかもしれません。 (v15.5では、警告を出すためにReact.createClassにはObject.definePropertyでgetterが設定されており、configurableでないので置き換えることはできません)

Deprecated React.PropTypes

これも、React.createClassと同様にずっと言われていましたが、prop-typesとして別パッケージとなり、v16ではreactから削除されます。

import PropTypes from 'prop-types';

そのためv15.5では、React.PropTypesを使おうとすると警告が出るようになりました。

これもcodemodが提供されているので、それを使って一括で変換することができます。

PropTypesに関しては、FlowやTypeScriptへの移行が勧められているもののハードルもあるので、別パッケージ化されたprop-typesをしばらく使い続けるのは選択肢としてあるのかなと思います。 今回別パッケージとなったのは組み込みのPropTypesのvalidationロジックであり、PropTypesのチェック機構自体がなくなることは、まだ予定されていないので。

ちなみに、将来的にAPIの変更が予定されているContextを使う場合にも、変わらずprop-typesを使って指定します。 (実際にはcontextTypesの定義でマスクしているだけなので、prop-typesを使う必要はないのですが)

Deprecated Addons

React本体がアドオンとして提供していた諸々が、廃止されたり別パッケージ化したり、移動したりしています。 v16では、react-with-addonsのUMDビルドも提供されなくなります。

  • react-addons-create-fragmentは、v16のFiber化により配列を返すことができるようになるため、多くの場面で不要となるので削除されます。
  • react-addons-css-transition-groupreact-addons-transition-groupは、react-transition-groupの別パッケージになりました。CSSTransitionGroupTransitionGroupして利用できます。ただし、全く実装が一緒というわけではないので移行する際には注意が必要です。すでに修正済みですが下記のようなバグとかもあったりするので...。
  • react-addons-linked-state-mixinreact-linked-inputは、明示的にvalueonChangeを指定すればいいので削除されます。
  • react-addons-pure-render-mixinreact-addons-shallow-compareは、React.PureComponentを代わりに利用できます。
  • react-addons-updateimmutability-helperが代わりに利用できます。

react-addons-test-utilsは、react-domのrendererに依存している部分が多いため、react-dom/test-utilsに移動されました。

import TestUtils from 'react-dom/test-utils';

ShallowRenderに関してはreact-domに依存していないため、react-test-renderer/shallowに移動されました。 ちなみにreact-test-rendererはJestがsnapshot testingで使っていたりする、ReactElementをJSONとして返すrendererです。 ShallowRenderは、これのトップレベルのComponentまでしかrenderしない版として考えることができます。

import {createRenderer} from 'react-test-renderer/shallow';

~~react-addons-perfだけは、特に何もなくこのままですが、react-addons-perfは同期的なrenderが前提となっているため、将来的にFiberで非同期的なrenderをする場合には正しく計測できません。~~

[修正] react-addons-perfは同期的なrenderが前提となっていてFiberへの対応が難しいため、v16(Fiber)への対応は行われません。 Perfに変わる何かについては検討されるので、将来的に何か提供される可能性もありますが、とりあえずは?react_perfによるBrowser Timelineを使った計測が推奨されています。

15.6(予定)

https://github.com/facebook/react/issues/9398

  • React.DOM.{p, div,...}として提供されていたファクトリ関数が廃止となります。
  • APIの廃止などの警告は、これまではconsole.errorとして出力されていましたが、console.warnで出力されるようになります。

16に向けて

v16はすでに@nextでインストールできます。 そのため、まだ実装されていないサーバーサイドレンダリングとShallowRenderを使っていない部分では試すことが可能です。

npm i react@next react-dom@next

Fiber

v16の一番大きな目玉は、Fiberに内部実装が置き換えられることです。 ただし、v16の時点ではFiberは現在のStackのrendererと互換性のあるモードで動作します。 そのため、Fiberの特徴であるrequestIdleCallbackによってスケジューリングされた非同期なrenderではなく、同期的なrenderとなるため、利用者として大きな違いは感じないかもしれません。 (call stack見ると全く変わっていることがわかると思いますが)

文字列や配列をComponentでラップすることなく直接返すことができるのは嬉しい部分かもしれません。

const Text = ({text}) => text;
const List = () => [1, 2, 3];

ちなみに、v16の時点でもReactDOM.unstable_deferredUpdatesを使うことで、非同期なrenderが出来るようにはなりそうです。 あとは、ReactDOMFiber.jsにあるuseSyncSchedulingというフラグを無理やりfalseにすればデフォルトで非同期なrenderになります。(軽く試した感じだと問題なく動いていた)

非同期のrenderをどのようにユーザー側のAPIとして見せるのかは、まだ明らかになっていなくてこれから議論していくようです。

Fiberについては、下記に集めたリソースを読むとわかると思います。(今後紹介的な何かを書くかも)

最初に見るものとしてのおすすめは、Lin ClarkによるA Cartoon Intro to Fiber(React.js Conf 2017)です。

互換モードによるFiber自体はfacebook.comでも問題なく動作しているようです。 ただし、サーバーサイドレンダリングに対する対応は、まだ全く入っておらず今後どうなっていくのかは不明です。FiberになるとStreaming renderingもやりやすくなるのではとは思いますが。

No more direct import!

v16からは、それぞれのエントリーポイントがRollupを使ってバンドルされたものになります。 なので下のような構造になります。

これにより、初期ロード時間の短縮やサーバーサイドでのパフォーマンスの向上が見込まれています。 また、利用者側には関係ないですがビルド周りが見直されており、GruntやgulpやBrowserifyのタスクがリポジトリから削除されています。すっきり。

この変更による、一番大きな影響はreact/lib/xxxxとして直接Reactの内部ライブラリを利用しているライブラリが動作しなくなることです。 enzymeなどのメジャーなライブラリはReact側でもケアされていますが、それ以外のライブラリーは壊れてどうにもならなくなることがあるかもしれません。 したがって、そのようなハックをしているライブラリーを利用している場合は注意した方がよさそうです。

リリース?

ちなみにv16は、夏くらい(?)をターゲットに考えているようです。

また何か動きがあれば追記するかも。