11
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

はじめに

過去の話になりますが、React Redux v6というものがありました。v5ではlegacy contextを使っていたのですが、React v16.3でContext APIが登場したため、それに追従したものです。その頃にはConcurrent Modeの計画もあり(当初はAsync Reactと呼ばれていました)、Context APIをうまく使うことで、Concurrent Modeにおけるある潜在的な問題(Tearingと呼ばれます)を解決できるはずとなりました。それは、Contextにstateを入れて、Reactに更新の伝搬を任せるという方法でした。

しかし、この方法はReact Hooksが登場して困ったことになりました。 Hooksで更新の伝搬を止める方法がなかったのです。React Reduxは止むなくcontextにstoreを入れる方法に戻してv7をリリースしました。Tearingの問題の解決はあきらめた形になります。

RFC 119

React Contextの更新の伝搬の問題を解決する方法としてuseContextSelectorが提案されています。

https://github.com/reactjs/rfcs/pull/119

React Redux界隈では期待されていますが、議論は進んでいません。この提案方式では、Tearingの問題だけでなく、stale propsの問題も解決できます。

use-context-selector

しかし、オープンソースの世界です。代替品を実装しました。

https://github.com/dai-shi/use-context-selector

userlandの実装では、stale propsは解決できないのですが、実際はそれほど問題にならないか、workaroundがあることが多いと思います。

使い方

import { createContext, useContextSelector } from 'use-context-selector';

const context = createContext(null);

React.createContextの代わりにライブラリからimportしたcreateContextを使います。

const StateProvider = ({ children }) => {
  const [state, setState] = useState({ count1: 0, count2: 0 });
  return (
    <context.Provider value={[state, setState]}>
      {children}
    </context.Provider>
  );
};

Providerの使い方は通常と同じです。

const Counter1 = () => {
  const count1 = useContextSelector(context, v => v[0].count1);
  const setState = useContextSelector(context, v => v[1]);
  const increment = () => setState(s => ({
    ...s,
    count1: s.count1 + 1,
  }));
  return (
    <div>
      <span>Count1: {count1}</span>
      <button type="button" onClick={increment}>+1</button>
    </div>
  );
};

contextを利用するコンポーネントでは、useContextの代わりにuseContextSelectorを使います。こうすることで、selectした結果が変わらない限り、context valueの更新の伝搬は止まります。

おわりに

実は、use-context-selectorの実装アイデアは、RFC119が提案されてから考えたわけではありません。react-trackedを実装する段階ですでに課題はあり、試行錯誤の上、実装していました。そこから、Proxyによるstate usage trackingを取り除いてシンプルにしたものが本ライブラリです。

Tearingの問題については、こちらのリポジトリにリンクやチェックツールがあるので、興味がある方はご覧ください。

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?