maesblog

React v16.4.0: Pointer Events をサポート【日本語翻訳】

2018年5月23日に React v16.4.0 がリリースされました。全バージョン v16.3.0 のリリースは2018年3月29日だったので、約2カ月ぶりのバージョンアップです。今回のリリースの目玉は、Pointer Events のサポートと、v16.3.0 で追加されたライフサイクルメソッドの getDerivedStateFromProps のバグ修正です。今回も React の公式ブログのリリースノート記事 React v16.4.0: Pointer Events を日本語に訳してみました。ぜひ参考にしていただければと思います。

react v16.4.0
React v16.4.0: Pointer Events – React Blog

May 23, 2018 by Andrew Clark

The latest minor release adds support for an oft-requested feature: pointer events!

今回のマイナーリリースでは、要望の多かった機能: Pointer Events を追加しています。

It also includes a bugfix for getDerivedStateFromProps. Check out the full changelog below.

さらに、getDerivedStateFromProps メソッドのバグ修正も含まれています。すべての変更履歴は以下で確認できます。

Pointer Events

The following event types are now available in React DOM:

以下は React DOM で利用可能なイベントの種類です。

  • onPointerDown
  • onPointerMove
  • onPointerUp
  • onPointerCancel
  • onGotPointerCapture
  • onLostPointerCapture
  • onPointerEnter
  • onPointerLeave
  • onPointerOver
  • onPointerOut

Please note that these events will only work in browsers that support the Pointer Events specification. (At the time of this writing, this includes the latest versions of Chrome, Firefox, Edge, and Internet Explorer.) If your application depends on pointer events, we recommend using a third-party pointer events polyfill. We have opted not to include such a polyfill in React DOM, to avoid an increase in bundle size.

まず、これらのイベントは、Pointer Events の仕様をサポートしているブラウザーでのみ動くということに注意してください(この記事を書いている時点では、Chrome、Firefox、Edge、Internet Explorer の最新版となります)。もし、アプリケーションが Pointer Events に依存していた場合、サードパーティの Pointer Events のポリフィルを使うことをお勧めします。React DOM ではこのようなポリフィルを含めないことに決めています。それはバンドルサイズが増えてしまうのを防ぐためです。

Check out this example on CodeSandbox.

CodeSandbox でサンプルをチェックしてください。

Huge thanks to Philipp Spiess for contributing this change!

この変更に貢献してくれた Philipp Spies 氏に感謝します。

Bugfix for getDerivedStateFromProps – getDerivedStateFromProps のバグ修正

getDerivedStateFromProps is now called every time a component is rendered, regardless of the cause of the update. Previously, it was only called if the component was re-rendered by its parent, and would not fire as the result of a local setState. This was an oversight in the initial implementation that has now been corrected. The previous behavior was more similar to componentWillReceiveProps, but the improved behavior ensures compatibility with React’s upcoming asynchronous rendering mode.

getDerivedStateFromProps は、更新の要因がなんであろうが、コンポーネントがレンダリングされる度に呼ばれます。これまでは、コンポーネントが親コンポーネントによって再レンダリングされた場合にのみ、呼ばれるようになっていました。そして、ローカルの setState の結果として発火することもありませんでした。これは初期実装時の対応漏れによるものでした(現在は修正されています)。これまでの動きはより componentWillReceiveProps に近かったのですが、改善の結果、React の来たる非同期レンダリングモード(Asynchronous Rendering Mode)との互換性が確保された動きになっています。

This bug fix will not affect most apps, but it may cause issues with a small fraction of components. The rare cases where it does matter fall into one of two categories:

このバグはほとんどのアプリには影響を及ぼしませんが、ほんのわずかなコンポーネントで発生しうる問題です。それが問題となる稀なケースは2つのカテゴリーのうちのどちらかとなります。

1. Avoid Side Effects in getDerivedStateFromProps – getDerivedStateFromProps の副作用を避ける

Like the render method, getDerivedStateFromProps should be a pure function of props and state. Side effects in getDerivedStateFromProps were never supported, but since it now fires more often than it used to, the recent change may expose previously undiscovered bugs.

render メソッドのように、getDerivedStateFromProps は props や state の純粋な関数であるべきです。getDerivedStateFromProps の副作用はサポートされるべきではありませんでしたが、以前よりも頻繁に発火されるようになっているので、変更の仕方によっては、これまでは見つからなかったバグも発生することがあるかもしれません。

Side effectful code should be moved to other methods: for example, Flux dispatches typically belong inside the originating event handler, and manual DOM mutations belong inside componentDidMount or componentDidUpdate. You can read more about this in our recent post about preparing for asynchronous rendering.

副作用を含んだコードは他のメソッドに移動させるべきです。たとえば、Flux の dispatch は通常元になったイベントハンドラーの中に属していて、手動の DOM ミューテーションは、componentDidMount または componentDidUpdate の中に属しています。詳細については、最近の投稿記事「preparing for asynchronous rendering」をお読みください。

2. Compare Incoming Props to Previous Props When Computing Controlled Values – 制御された値を処理する時に、入ってくる Porps と以前の Props を比較する

The following code assumes getDerivedStateFromProps only fires on prop changes:

以下のコードを見ると、getDerivedStateFromProps は props の変更でのみ発火すると思うでしょう。

static getDerivedStateFromProps(props, state) {
  if (props.value !== state.controlledValue) {
    return {
      // Since this method fires on both props and state changes, local updates
      // to the controlled value will be ignored, because the props version
      // always overrides it. Oops!
      // このメソッドは props と state のどちらの変更でも発火するので、
      // 制御された値へのローカル上の更新は無視されます。
      // なぜなら、props のバージョンは常にそれを上書きするからです。
      controlledValue: props.value,
    };
  }
  return null;
}

One possible way to fix this is to compare the incoming value to the previous value by storing the previous props in state:

これを解決するひとつの方法は、入ってくる値と以前の値を、以前の props を state に格納することによって比較することです。

static getDerivedStateFromProps(props, state) {
  const prevProps = state.prevProps;
  // Compare the incoming prop to previous prop
  // 入ってくる prop と 以前の prop を比較
  const controlledValue =
    prevProps.value !== props.value
      ? props.value
      : state.controlledValue;
  return {
    // Store the previous props in state
    // 以前の props を state に格納
    prevProps: props,
    controlledValue,
  };
}

However, try to avoid mixing props and state in this way — it’s rare that state needs to duplicate a value that exists in props and doing so can lead to subtle bugs. Prefer to have one source of truth for any value, and lift state up if necessary to share it between multiple components. Most uses of getDerivedStateFromProps (and its predecessor componentWillReceiveProps) can be fixed by moving the state management to a parent component.

しかし、この方法で props と state を混合するのを避けるようにしてください。- つまり、props に存在する値を state が複製する必要があるのは稀であり、そのようにすることは、些細なバグを産みやすくします。どんな値に対しても真のソースをひとつ持つようにしてください。そして、もし複数のコンポーネント間でその値を共有する必要があるのであれば、lift state up(親に持ち上げて親の state で管理) するようにしてください。state の管理を親コンポーネントに移動することにより、getDerivedStateFromProps(とその前身の componentWillReceiveProps)のほとんどの用途で fix 可能となります。

Please remember that most components do not need getDerivedStateFromProps. It’s not meant to serve as a one-to-one replacement for componentWillReceiveProps. We’ll publish a follow-up post in the coming weeks with more recommendations on how to use (and not use) getDerivedStateFromProps.

ほとんどのコンポーネントは、getDerivedStateFromProps を必要としないということを忘れないようにしてください。getDerivedStateFromProps は、componentWillReceiveProps を1対1で置き換えるものではありません。どのように getDerivedStateFromProps を使うか(そして使わないか)について今後数週間でフォローアップ記事を公開する予定です。

Installation – インストール方法

React v16.4.0 is available on the npm registry.

React v16.4.0 は、npm レジストリーで利用可能です。

To install React 16 with Yarn, run:

Yarn で React 16 をインストールする場合は、以下を実行します。

yarn add react@^16.4.0 react-dom@^16.4.0

To install React 16 with npm, run:

npm で React 16 をインストールする場合は、以下を実行します。

npm install --save react@^16.4.0 react-dom@^16.4.0

We also provide UMD builds of React via a CDN:

CDN を通して React の UMD ビルドも用意しています。

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

Refer to the documentation for detailed installation instructions.

詳細なインストール手順についてのドキュメントもご確認ください。

Changelog – 変更履歴

React

  • Add a new experimental React.unstable_Profiler component for measuring performance. (@bvaughn in #12745)

    パフォーマンス計測用に新しい実験的な React.unstable_Profiler コンポーネントを追加しました(@bvaughn in #12745)。

React DOM

  • Add support for the Pointer Events specification. (@philipp-spiess in #12507)

    Pointer Events の仕様のサポートを追加しました(@philipp-spiess in #12507)。

  • Properly call getDerivedStateFromProps() regardless of the reason for re-rendering. (@acdlite in #12600 and #12802)

    再レンダリングの利用に関わらず、getDerivedStateFromProps() が適切に呼ばれるようになりました(@acdlite in #12600 and #12802)。

  • Fix a bug that prevented context propagation in some cases. (@gaearon in #12708)

    いくつかのケースでコンテキストの伝播を防いでいたバグを修正しました(@gaearon in #12708)。 

  • Fix re-rendering of components using forwardRef() on a deeper setState(). (@gaearon in #12690)

    setState() の下層にある forwardRef() を使用しているコンポーネントの再レンダリングを修正しました(@gaearon in #12690)。

  • Fix some attributes incorrectly getting removed from custom element nodes. (@airamrguez in #12702)

    カスタム要素のノードから間違って取り除かれているいくつかの属性を修正しました(@airamrguez in #12702)。

  • Fix context providers to not bail out on children if there’s a legacy context provider above. (@gaearon in #12586)

    古い Context Provider が上部にあった場合、子コンポーネントでブロックされてしまう Context Provider を修正しました(@gaearon in #12586)。

  • Add the ability to specify propTypes on a context provider component. (@nicolevy in #12658)

    context provider コンポーネントに propTypes を指定できるようにしました(@nicolevy in #12658)。

  • Fix a false positive warning when using react-lifecycles-compat in <StrictMode>. (@bvaughn in #12644)

    <StrictMode>react-lifecycles-compat を使用する時に出る誤った警告メッセージを修正しました(@bvaughn in #12644)。

  • Warn when the forwardRef() render function has propTypes or defaultProps. (@bvaughn in #12644)

    forwardRef()  の render 関数が propTypes または defaultProps を持った時に警告を出すようにしました(@bvaughn in #12644)。

  • Improve how forwardRef() and context consumers are displayed in the component stack. (@sophiebits in #12777)

    コンポーネントのスタックの中での forwardRef() や Context Consumer の表示方法を改善しました(@sophiebits in #12777)。

  • Change internal event names. This can break third-party packages that rely on React internals in unsupported ways. (@philipp-spiess in #12629)

    内部のイベント名を変更しました。サポートされていない方法で React の内部に依存しているサードパーティのパッケージには影響があります(@philipp-spiess in #12629)。

React Test Renderer

  • Fix the getDerivedStateFromProps() support to match the new React DOM behavior. (@koba04 in #12676)

    新しい React DOM の振る舞いにマッチするように getDerivedStateFromProps() のサポートを修正しました(@koba04 in #12676)。

  • Fix a testInstance.parent crash when the parent is a fragment or another special node. (@gaearon in #12813)

    親コンポーネントが fragment もしくは 他の特別なノードだった時に testInstance.parent がクラッシュするのを修正しました(@gaearon in #12813)。

  • forwardRef() components are now discoverable by the test renderer traversal methods. (@gaearon in #12725)

    forwardRef() コンポーネントも、テストのレンダラであるトラバーサルメソッドによって発見可能となりました(@gaearon in #12725)。

  • Shallow renderer now ignores setState() updaters that return null or undefined. (@koba04 in #12756)

    Shallow レンダラは、null または undefined を返す setState() のアップデータを無視するようになりました(@koba04 in #12756)。

React ART

  • Fix reading context provided from the tree managed by React DOM. (@acdlite in #12779)

    React DOMによって管理されているツリーから提供される Context の読み込みを修正しました(@acdlite in #12779)。

React Call Return (Experimental)

  • This experiment was deleted because it was affecting the bundle size and the API wasn’t good enough. It’s likely to come back in the future in some other form. (@gaearon in #12820)

    バンドルサイズに影響を及ぼし、API は十分に良いものとならなかったので、この実験的な試みは削除しました。将来的には別の形で戻ってくるかもしれません(@gaearon in #12820)。

React Reconciler (Experimental)

  • The new host config shape is flat and doesn’t use nested objects. (@gaearon in #12792)

    新しい host config  shape はフラットになり、ネストされたオブジェクトを使うのをやめました(@gaearon in #12792)。

まとめ

React も v16 になってから、結構複雑化してきているような印象です。普段から新しい書き方で React を書いていないと、付いていけなくなりそうです。v16 以降で追加された書き方をまとめておきたいところです。

さて、今回の v16.4.0 では、まず Pointer events がサポートされました。Pointer Event は、いわゆるポインタを使ったデバイスのイベントを扱うための仕様です。これまでは主にマウスを念頭に仕様が決められていましたが、現在はタッチスクリーン、スタイラスペンなど入力デバイスが多岐に渡っています。こうしたポインタデバイスのイベントをまとめて扱うには抽象化が必要ということで、策定されたのが Pointer events ということです。今回 React でこの Pointer events がサポートされたということで、これまで以上に表現豊かな UI の実装が可能となったと言えます。

それから、もうひとつの目玉として、getDerivedStateFromProps のバグ修正が紹介されていましたが、それほど利用頻度は高くないライフサイクルメソッドだと思っていますが、どうでしょうか。componentWillReceiveProps の代わりに追加されたメソッドで、コンポーネントのマウント時と更新時に呼ばれるメソッドです。このメソッドの特徴は、返した値で、state の値を更新できるということです。いわゆる setState の機能を持っています。直前の props が受け取れないなど使い方に難がありますが、記事にもあったように、どのように使ったら良いかの記事が数週間後に投稿されるということなので、ぜひ参考にしたいところです。

追記(2018年6月10日): 早速6月7日に、componentWillReceiveProps に関する記事が React Blog に投稿されましたので、紹介しておきます。参考にしてください。

v16以降のリリース内容を見ていると、React はこの1年でガラッと変わりそうな気がします。最近は仕事ではほぼAngularの人になってしまっているので、頑張って付いていかねばと思っています。

コメント

  • 必須

コメント