LoginSignup
8
8

More than 5 years have passed since last update.

redux-aggregate v2 - Action / Reducer の分割 -

Last updated at Posted at 2018-08-13

redux-aggregate が v2 になりました。主な変更点は以下の通りで、v1 からの Breaking Change はありません。アプリケーションスケールアップの際に効果が期待出来る変更を追加しています。

  • createActions の追加
  • Aggregate.subscribe の追加
  • subscriptions 概念の追加

これからは createAggregate で生成された ボイラープレートでも、reducer / action が多対多の関係を持つことが可能になります。もちろん新しく追加されたAPIも、必要最小限の型定義から推論型を導出します。

createActions

従来の ActionCreator 定義を確認してみましょう。ActionType と payload が結合していますね。

actions/timer.js
function tick (message) {
  const date = new Date()
  if (message !== undefined) return { type: 'TIMER_TICK', pyload: { date }}
  return { type: 'TIMER_TICK', payload: { date, message }}
}

ここから ActionType を取り除き、payload だけを return するものを actionSrc と呼んでいます。in/out があるだけのただの純関数であることが分かります

actions/timer.js
// @ ActionSources

function tick (message) {
  const date = new Date()
  if (message !== undefined) return { date }
  return { date, message }
}
export const TimerAC = { tick }

createAggregate と同様に、ActionSources / namespace を付与し createActions を call します。

store.js
import { createActions } from 'redux-aggregate'
import { ActionSources } from 'path/to/actions/timer'

const Timer = createActions(ActionSources, 'timer/')
const {
  types,    // ActionTypes
  creators, // ActionCreators
} = Timer

createActions では reducerFactory は生成されません。

Aggregate.subscribe

createAggregate で生成された Aggregate インスタンスに、subscribe というメソッドが生えました。このメソッドで上述の Actions を購読します。購読に応じた変更処理は後述の subscriptions に書いていきます。

store.js
import { TimerActions } from 'path/to/actions/timer'
import { TodosMutations, TodosSubscriptions } from 'path/to/models/todos'
export const Timer = createActions(TimerActions, 'timer/')
export const Todos = createAggregate(TodosMutations, 'todos/')

Todos.subscribe(
  Timer,  // Actions or Aggregate
  TodosSubscriptions.Timer  // Subscriptions
)

一般的な subscribe とは少し異なり、これは reducerFactory を拡張するものです(うっかり多重 subscribe したところで、違いはありません)。

subscriptions

mutations が定義されているモデルファイルに、購読マップ(subscriptions)を定義します。見た目は mutations とそっくりですが、ActionType / ActionCreator を生成しません。subscription 単体は、従来の switch文で選り分けられた先の reducer と等価です。

注意しなければいけないのは、subscription は規約を守らなければ、型エラーが発生します。一体何の規約かというと、それは開発者自身が定義したメソッド名・payload に則るということです。

example で示しているとおり、TimerActions の tick というメソッド名・メソッド戻り値を第2引数にとることが subscription関数に期待されます。第1引数は TodosState を指します。modelファイルに定義される全関数は、所属する state を中心に回ります。

actions/timer.js
// subscription の名称は tick に制約される
function tick (message) {
  const date = new Date()
  if (message !== undefined) return { date }
  return { date, message }
}
// subscription の第二引数は { date } か { date, message } に制約される
models/todos.js
const TodosSubscriptions = {
  Timer: {
    tick(state, { date, message }) {
      if (message !== undefined) {
        return { ...state, date, messageFromTimer: message }
      }
      return { ...state, date }
    }
  }
}

他のメディアでも発信していますが、このライブラリの最大の利点は、「アプリケーションの核が純粋な言語仕様のみで確立されていること・ Redux の概念が介入していないこと」であり、コード・付随テストの寿命を伸ばす大事なことだと筆者は考えています。

利用シーン

概念が増えたことで少しややこしくなりましたが、今回の追加機能は必要に応じて導入、スケールアップのシーンで役立てて下さい。はじめは 単体Aggregte の関心事であった Action が、他のAggregate の関心事となったタイミングで利用すると良いかと思います。

Aggregate.subscribe は 他Aggregate の Action も購読出来ます。2つのAggregate の関心ごとになった際には、下流が上流を購読すれば、それで十分です。それより多くの関心事となった場合や、当初から多くの関心事であると想定された場合は、createActions を使って「Action のみの集約」を作ってください。

Action を全く持つ必要のない集約の場合、createSubscriberを使って「Reducer のみの集約」を作ってください。example ->

公式Document を公開しました https://redux-aggregate.js.org/

8
8
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
8
8