6
3

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 3 years have passed since last update.

【React】Immutable.js から Immer へ切替

Last updated at Posted at 2020-12-08

なぜ

ずっと immutable.js 使ってますが、OOP アプローチに関して、最新何かあるかを探したことろ、immer が見つかった。なんと、React open source award 2020 の Breakthrough of the year を受賞されたようです。

どっちが良い

現時点、どっちもメジャーな OOP アプローチです。immutable.js は Facebook が管理するライブラリで、結構年数ありました。過去2年のダウンロード数から見ると、最近は immer が波に乗ってます。サイズやパフォーマンス的にも immer が良さそうです。

image.png

個人感想のメリット

immutable.jsredux 用のライブラリで、immerReact.setState にも使えます。
type の定義が必要なくて、楽になって、コード量は大きく減ってませんが、可読性が向上したと思います。

変更点 - Settings

redux-immutableconnected-react-routerimmutable ライブラリが必要なくなります。

変更点 - Reducer

reducer から見ると、import のみ変わって、ほとんど修正必要ありません。

reducer-immutable.js
import { handleActions, Action } from 'redux-actions';
import { AppState } from '@domains';
import { ActionTypes } from '@constants';
import { App01Payload, App02Payload } from '@actions/app';

const app = handleActions<AppState, any>(
  {
    [ActionTypes.APP_PLUS_REQUEST]: (state: AppState) => state,
    [ActionTypes.APP_PLUS_SUCCESS]: (state: AppState, { payload: { num } }: Action<App01Payload>) => state.plus(num),
    [ActionTypes.APP_PLUS_FAILURE]: (state: AppState) => state,

    [ActionTypes.APP_MINUS_REQUEST]: (state: AppState) => state,
    [ActionTypes.APP_MINUS_SUCCESS]: (state: AppState, { payload: { num } }: Action<App02Payload>) => state.minus(num),
    [ActionTypes.APP_MINUS_FAILURE]: (state: AppState) => state,
  },

  new AppState()
);

export default app;
reducer-immer
import { handleActions, Action } from 'redux-actions';
import { AppState } from '@domains';
import { ActionTypes } from '@constants';
import { App01Payload, App02Payload } from '@actions/app';

const app = handleActions<AppState, any>(
  {
    [ActionTypes.APP_PLUS_REQUEST]: (state: AppState) => state,
    [ActionTypes.APP_PLUS_SUCCESS]: (state: AppState, { payload: { num } }: Action<App01Payload>) => state.plus(num),
    [ActionTypes.APP_PLUS_FAILURE]: (state: AppState) => state,

    [ActionTypes.APP_MINUS_REQUEST]: (state: AppState) => state,
    [ActionTypes.APP_MINUS_SUCCESS]: (state: AppState, { payload: { num } }: Action<App02Payload>) => state.minus(num),
    [ActionTypes.APP_MINUS_FAILURE]: (state: AppState) => state,
  },

  new AppState()
);

export default app;

変更点 - ロジック

従来の typescript type 定義が省略できるので、少し楽になります。書き方も immutable.js 独自の方法じゃなく、ES6 が書けます。

immutable.js
import { Record } from 'immutable';

export interface IApp extends AppProps, Record<AppProps> {
  get<K extends keyof AppProps>(key: K): AppProps[K];
}

export interface AppUIProps {}

export interface AppProps extends AppUIProps {
  // count
  count: number;
}

/**
 * App
 */
export default class AppState extends Record<AppProps>({
  count: 0,
}) {
  plus(num: number) {
    return this.set('count', this.count + num);
  }

  // inner update
  minus(num: number) {
    return this.set('count', this.count - num);
  }
}
immer
import { immerable, produce } from 'immer';

export default class AppState {
  [immerable] = true;

  count: number = 0;

  plus = (num: number) =>
    produce(this, (draft) => {
      draft.count += num;
    });

  minus = (num: number) =>
    produce(this, (draft) => {
      draft.count -= num;
    });
}

おまけ

immer公式ドキュメントは詳しく色んな情報書いています。

immer 取り込み済みのプロジェクトは GitHub 公開中です。

6
3
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
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?