maesblog

React v16.3.0: 新しいLifecycleメソッドとcontext API【日本語翻訳】

3月29日に待望のReact v16.3.0がリリースされました。前回のv16.2.0のリリースから約5ヶ月が経ちます。今回の目玉機能はcontext APIと言われていましたが、ライフサイクルメソッドの変更や、ref周りの機能強化などマイナーバージョンアップにしては大きなリリース内容となっています。しっかり把握するためにReactの公式ブログの記事「React v16.3.0: New lifecycles and context API」を訳してみました。

React v16.3.0: New lifecycles and context API
React v16.3.0: New lifecycles and context API

March 29, 2018 by Brian Vaughn

A few days ago, we wrote a post about upcoming changes to our legacy lifecycle methods, including gradual migration strategies. In React 16.3.0, we are adding a few new lifecycle methods to assist with that migration. We are also introducing new APIs for long requested features: an official context API, a ref forwarding API, and an ergonomic ref API.

数日前に、 緩やかな移行戦略を含む、レガシーなライフサイクルメソッドに対する変更について投稿しました。React 16.3.0において、この移行を支援するためにいくつかのライフサイクルメソッドを追加しています。さらに、長い間リクエストされていた機能に対する新しいAPI(公式のcontext API、ref forwarding API、ergonomic ref API)を導入しています。

Read on to learn more about the release.

当記事に目を通し、リリース詳細を学んでください。

Official Context API – 公式のContext API

For many years, React has offered an experimental API for context. Although it was a powerful tool, its use was discouraged because of inherent problems in the API, and because we always intended to replace the experimental API with a better one.

この数年の間に、Reactはcontextのための実験的なAPIを提供してきました。これは強力なツールでしたが、APIに固有の問題があり満足のいくものではありませんでした。それ故、常にこの実験的なAPIをより良いものへと置き換えることを目指してきました。

Version 16.3 introduces a new context API that is more efficient and supports both static type checking and deep updates.

バージョン16.3ではより有能な新しいcontext APIと、静的型チェックとディープアップデートの両方のサポートを提供します。

Note
The old context API will keep working for all React 16.x releases, so you will have time to migrate.

注意
古いcontext APIは、移行するための時間を持てるように、すべてのReact 16.xのリリースの間は動き続けるようにします。

Here is an example illustrating how you might inject a “theme” using the new context API:

以下は、新しいcontext APIを使用して「theme(テーマ)」を挿入する方法を示す例です。

const ThemeContext = React.createContext('light');

class ThemeProvider extends React.Component {
  state = {theme: 'light'};

  render() {
    return (
      <ThemeContext.Provider value={this.state.theme}>
        {this.props.children}
      </ThemeContext.Provider>
    );
  }
}

class ThemedButton extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {theme => <Button theme={theme} />}
      </ThemeContext.Consumer>
    );
  }
}

Learn more about the new context API here.

新しいcontext APIのについての詳細はこちら。

createRef API

Previously, React provided two ways of managing refs: the legacy string ref API and the callback API. Although the string ref API was the more convenient of the two, it had several downsides and so our official recommendation was to use the callback form instead.

これまでReactはrefsの管理方法として2つの方法(レガシーなstring ref APIとcallback API)を提供してきました。string ref APIの方がcallback APIより便利でしたが、いくつかの欠点があり、公式では代わりにcallback APIの使用を推奨してきました。

Version 16.3 adds a new option for managing refs that offers the convenience of a string ref without any of the downsides:

バージョン16.3では、refsの管理に関して、欠点のないstring ref APIの便利さを提供する新しいオプションを追加しました。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.inputRef = React.createRef();
  }

  render() {
    return <input type="text" ref={this.inputRef} />;
  }

  componentDidMount() {
    this.inputRef.current.focus();
  }
}

Note:
Callback refs will continue to be supported in addition to the new createRef API.

You don’t need to replace callback refs in your components. They are slightly more flexible, so they will remain as an advanced feature.

注意
callback refs APIは、新しいcreateRef APIに加えてサポートされ続けます。

現在のコンポーネントで使用しているcallback refs APIは置き換える必要はありません。柔軟性があるので、高度な機能として残す予定です。

Learn more about the new createRef API here.

新しいcreateRef APIのについての詳細はこちら。

forwardRef API

Higher-order components (or HOCs) are a common way to reuse code between components. Building on the theme context example from above, we might create an HOC that injects the current “theme” as a prop:

Higher-order components (HOCs) はコンポーネント間のコードを再利用するための一般的な方法です。上記のtheme contextの例を元に、propsとして現在の「theme」を注入するHOCを作成したとすると以下のようになります。

function withTheme(Component) {
  return function ThemedComponent(props) {
    return (
      <ThemeContext.Consumer>
        {theme => <Component {...props} theme={theme} />}
      </ThemeContext.Consumer>
    );
  };
}

We can use the above HOC to wire components up to the theme context without having to use ThemeContext directly. For example:

以下のように、上記のHOCを使用すると、直接ThemeContextを使用する必要なく、theme context以下のコンポーネントを作成することができます。

class FancyButton extends React.Component {
  buttonRef = React.createRef();

  focus() {
    this.buttonRef.current.focus();
  }

  render() {
    const {label, theme, ...rest} = this.props;
    return (
      <button
        {...rest}
        className={`${theme}-button`}
       ref={this.buttonRef}>

        {label}
      </button>
    );
  }
}

const FancyThemedButton = withTheme(FancyButton);

// We can render FancyThemedButton as if it were a FancyButton
// It will automatically receive the current "theme",
// And the HOC will pass through our other props.
// FancyThemedButtonをFancyButtonであるかのようにレンダリングできます。
// 自動的に現在の「theme」を受け取り、HOCはそれを他のpropsに渡します。
<FancyThemedButton
  label="Click me!"
  onClick={handleClick}
/>;

HOCs typically pass props through to the components they wrap. Unfortunately, refs are not passed through. This means that we can’t attach a ref to FancyButton if we use FancyThemedButton— so there’s no way for us to call focus().

HOCは、一般的にそれらがラップしているコンポーネントにpropsを渡します。残念なことに、refsは渡されません。これはFancyThemedButtonを使用したい時に、refをFancyButtonに付与できないということを意味します。つまり、focus()を呼ぶ術がありません。

The new forwardRef API solves this problem by providing a way for us to intercept a ref and forward it as a normal prop:

新しいforwardRef APIは、refをインターセプト(横取り)し、通常のpropsとして渡す方法を提供することで、この問題を解決しています。

function withTheme(Component) {
  // Note the second param "ref" provided by React.forwardRef.
  // We can attach this to Component directly.
  // React.forwardRefによって渡される第二引数の「ref」に注目してください。
  // この「ref」を直接コンポーネントに付与できます。
  function ThemedComponent(props, ref) {
    return (
      <ThemeContext.Consumer>
        {theme => (
          <Component {...props} ref={ref} theme={theme} />
        )}
      </ThemeContext.Consumer>
    );
  }

  // These next lines are not necessary,
  // But they do give the component a better display name in DevTools,
  // e.g. "ForwardRef(withTheme(MyComponent))"
  // 以下の行は必要ありませんが、
  // コンポーネントにDevTools上でのより良い表示名を与えます。
  // 例: "ForwardRef(withTheme(MyComponent))"
  const name = Component.displayName || Component.name;
  ThemedComponent.displayName = `withTheme(${name})`;

  // Tell React to pass the "ref" to ThemedComponent.
  // ThemedComponentに「ref」を渡すように、Reactに伝えます。
  return React.forwardRef(ThemedComponent);
}

const fancyButtonRef = React.createRef();

// fancyButtonRef will now point to FancyButton
// fancyButtonRefはFancyButtonを指すようになります。
<FancyThemedButton
  label="Click me!"
  onClick={handleClick}
  ref={fancyButtonRef}
/>;

Component Lifecycle Changes – コンポーネントのライフサイクルの変更

React’s class component API has been around for years with little change. However, as we add support for more advanced features (such as error boundaries and the upcoming async rendering mode) we stretch this model in ways that it was not originally intended.

Reactのclass component APIは長い間ほとんど変わってきませんでした。しかし、より高度な機能(error boundariesや来たるasync rendering modeなど)のサポートを追加するにつれ、当初は意図していなかった方法でこのモデルは拡張されています。

For example, with the current API, it is too easy to block the initial render with non-essential logic. In part this is because there are too many ways to accomplish a given task, and it can be unclear which is best. We’ve observed that the interrupting behavior of error handling is often not taken into consideration and can result in memory leaks (something that will also impact the upcoming async rendering mode). The current class component API also complicates other efforts, like our work on prototyping a React compiler.

例えば、現在のAPIを使うと、どうでもいいロジックで簡単に初期レンダリングをブロックすることができます。この理由の一つとしては、与えられたタスクを実行する方法がいくつもあり、どれが最善の方法なのか曖昧であるためです。エラーハンドリングの割込処理がちゃんと考慮されてなく、メモリリーク(いくつかは来たるasync rendering modeにも影響を及ぼすでしょう)を引き起こすことをよく見てきました。さらに現在のclass component APIは、われわれのReactコンパイラのプロトタイピングなどの取り組みを複雑にします。

Many of these issues are exacerbated by a subset of the component lifecycles (componentWillMount, componentWillReceiveProps, and componentWillUpdate). These also happen to be the lifecycles that cause the most confusion within the React community. For these reasons, we are going to deprecate those methods in favor of better alternatives.

これらの問題の多くは、コンポーネントのライフサイクル(componentWillMountcomponentWillReceivePropscomponentWillUpdate)のサブセットによって悪化します。さらに、これらはReactのコミュニティ内で最も混乱を引き起こすライフサイクルでもあります。これらの理由から、より良い代替手段を用意し、これらのメソッドを非推奨としていく予定です。

We recognize that this change will impact many existing components. Because of this, the migration path will be as gradual as possible, and will provide escape hatches. (At Facebook, we maintain more than 50,000 React components. We depend on a gradual release cycle too!)

この変更は既存のコンポーネントの多くに影響を及ぼすことは認識しています。従って、移行の方針もできるだけ緩やかなものとなるようにし、エスケープハッチ(逃げ道)も提供していく予定です。(Facebookでは、50,000を超えるReactコンポーネントを維持しています。Facebookでも緩やかなリリースサイクルに頼ることになります。)

Note:
Deprecation warnings will be enabled with a future 16.x release, but the legacy lifecycles will continue to work until version 17.
Even in version 17, it will still be possible to use them, but they will be aliased with an “UNSAFE_” prefix to indicate that they might cause issues. We have also prepared an automated script to rename them in existing code.

注意
非推奨の警告は今後の16.xリリースにおいて表示されるようになりますが、レガシーなライフサイクルはバージョン17まで動作し続ける予定です

バージョン17でも、これらのライフサイクルを使用することを可能としますが、使用する際は、問題を引き起こすかもしれないということを示すために「UNSAFE_」という接頭辞をつけるようになります。既存のコード内にあるこれらの名前を変更するための自動スクリプトを用意してきました。

In addition to deprecating unsafe lifecycles, we are also adding a couple of new lifecyles:

安全でないライフサイクルを非推奨とするのに加え、新しい2つのライフサイクルを追加しています。

・getDerivedStateFromProps is being added as a safer alternative to the legacy componentWillReceiveProps.
・getSnapshotBeforeUpdate is being added to support safely reading properties from e.g. the DOM before updates are made.

  • getDerivedStateFromPropsは、レガシーなcomponentWillReceivePropsのより安全な代替手段として追加されています。
  • getSnapshotBeforeUpdateは、例えば更新がなされる前のDOMからプロパティを安全にレンダリングすることをサポートするために追加されています。

Learn more about these lifecycle changes here.

これらのライフサイクルの変更についての詳細はこちら。

StrictMode Component

StrictMode is a tool for highlighting potential problems in an application. Like Fragment, StrictMode does not render any visible UI. It activates additional checks and warnings for its descendants.

StrictModeは、アプリケーションの潜在的な問題をハイライトしてくれるツールです。Fragmentのように、StrictModeは、目に見えるUIをレンダリングしません。子孫コンポーネントのために追加のチェックと警告をアクティブ化します。

Note:
StrictMode checks are run in development mode only; they do not impact the production build.

注意
StrictModeのチェックは、development modeのみ実行されます。production buildには影響しません。

Although it is not possible for strict mode to catch all problems (e.g. certain types of mutation), it can help with many. If you see warnings in strict mode, those things will likely cause bugs for async rendering.

strict modeがすべての問題(例えば、mutationの特定の型など)をキャッチすることはできませんが、多くの場面で役に立つはずです。もしstrict modeで警告が出たとしたら、async renderingのバグが発生する可能性があります。

In version 16.3, StrictMode helps with:

バージョン16.3において、StrictModeは以下を行ってくれます。

・Identifying components with unsafe lifecycles
・Warning about legacy string ref API usage
・Detecting unexpected side effects

  • 安全でないライフサイクルを持ったコンポーネントの特定
  • レガシーなstring ref APIの使用についての警告
  • 予期しない副作用の検知

Additional functionality will be added with future releases of React.

Reactの今後のリリースで、さらなる機能が追加される予定です。 

Learn more about the StrictMode component here.

StrictMode componentについての詳細はこちら。

まとめ

翻訳は以上です。ここからは私の感想です。React v16.2で改善されたFragmentもそうでしたが、今回のv16.3で追加されたAPIなどを見ると、Reactもだいぶ複雑になりつつあるなと感じます。それだけ多くの案件で採用され、様々な用途で使われているということでしょう。つまり、そうした多種多様なケースに対応できるように進化し続けているように思います。今後もしばらくはこうした流れは続いていくのではないでしょうか。

開発する案件によっては、今回追加されたAPIなどは必要のない機能かもしれませんが、ライフサイクルの変更などはしっかりと抑えておく必要があるかと思います。ちょうど今回のリリース内容についてわかりやすい日本語の記事がありましたので、最後に紹介しておきます(仕事が速い)。

関数型プログラミング的な手法がバンバン取り入れられてきていますし、油断しているとついていけなくなりそうなので、しっかり勉強しておきたいと思っているところです。

コメント

  • 必須

コメント