Reduxの非同期処理に関して

前に書いたReduxに関する記事 では 最後の方 に 適当に書いてただけですが, もうちょいまともに書いてみて多少理解が深まったのでメモ。

非同期処理は Action に書く?

(以下 action と書いてますが action creator と同義で使っています)

よく「非同期処理は action に書け」的な話を聞きますし、 Reduxのgithub page にも actions.js に書いてます。

ただここでよくわからなくなるのが、非同期処理を行う action に関しては同期のものと違い、 pure object を返すものではない、ということ。

これに関しては redux-thunk (thunk は「互換性のないものを動くようにするもの」くらいの認識でいいのかな?) を middelware として使用します。

こいつを使うことで非同期処理を行う関数も action として使用することができます。(そういうことになってます)

Example

以下よく見るテンプレ。

// actions.js

// fetchingPost, receivePost はそれぞれ従来の action

export function fetchPost(id) {
  return (dispatch, getState) => {
    dispatch(fetchingPost())

    return fetch(`https://example.com/posts/${id}`)
      .then(res => res.json())
      .then(json => dispatch(receivePost(json)))
  }
}

非同期処理を行う action (function) は以下を満たしておけばよさそう

  • (store.)dispatch, (store.)getState を引数にとる関数を返す
    • 第二引数の getState はoptional で別になくてもいい
    • getState は現在のstateを取得したい時用(多分)

( dispatch を引数に取る関数の返り値が Promise じゃないといけないかなーと思ってましたが、別にその必要はないみたいです。 )

プラスで request の送信前、受信後にそれぞれ dispatch してあげるのが基本ぽい。 前者はめんどくさくて省略してしまうことが多そう…

とにかくめんどくさいし直感的じゃないという感じがして苦手です。 loading 画像を表示する component と action を用意しといて毎回それ使うとかにしておけばそこまでめんどくさくないかな?

あと他の action と動きが違うので「同じ action」という見方をしてしまっていいのかも疑問

Without fetch API

fetch 自体まだ本番で使ったことないので, ローカルでサクッと非同期処理試してみたいって人は以下のような方法でやるといいかも

// actions.js

export function fetchPost(id) {
  return (dispatch, getState) => {
    dispatch(fetchingPost())

    return new Promise((resolve) => {
      setTimeout(() => {
        dispatch(receivePost(dummyJsonPosts))
        resolve()
      }, 2000)
    })
  }
}

豆知識

// Date.prototype.toLocaleString()
// Ruby の strftime 的なのを毎回どうするか悩んでて, 細かく format 調整する必要がないならこれ使う。
// が、 Safari とか Mobile のほとんどのブラウザは option が未サポートっぽいので厳しい...
const d = new Date()
d.toLocaleString("ja-JP")     // => "2016/5/26 11:31:57"
d.toLocaleDateString("ja-JP") // => "2016/5/26"
d.toLocaleTimeString("ja-JP") // => "11:31:57"`

// console.table()
// [ みたいなリストの中身まで見たい時とかに便利
const arr = [
  { id: 1, name: "mmyoji" },
  { id: 2, name: "foo" },
]
console.table(arr) //=> いい感じに表示

// Array.prototype.filter
// Ruby で言う Array#select
arr.filter((item) => item.id > 1)
//=> [{ id: 2, name: "foo" }]

Chrome だと class, arrow function, let, const, etc. と一通り実装されてきつつあって, 最近 module も試そうと思えばいけるとかって記事も見たので babel いらなくなる日も近いんじゃないか、とか思ったり。

Redux はなんか実装が剥き出しになってる感じがしてどうもあまり好きになれないですね… 必要に迫られない限りは使いたくないです :sob: もうちょっとバカにも使いやすいFW誰か考えてくれ :pray:

Contents