【React Native】お前はReduxの何を知っているんだ?
僕はReduxの何を知っているんだろう…
こんばんは、JavaScript一筋だったけどそろそろサーバサイドも勉強したいじゅぎのんです。
最近React nativeでのアプリ制作も慣れてきて、会社のプロジェクトに混ざっていろいろとタスクをもらうことが多かったんですが、自社のアプリ開発のフロント側を割とウエイト重めで任されて、その中でもRedux+Redux sagaに悪戦苦闘している毎日です。
今日はそんなReduxを少しでも理解するために復習もかねて記事にしたいと思います。
Reduxとは?
A predictable state container for JavaScript apps. (Redux公式)
直訳するとJavaScript appのための予測可能なstateのコンテナ。意味わかんねえ。
要するに、JavaScriptで開発している時にほぼ確実に使うことになるstateの管理をまとめてしてくれるフレームワークです。
Reduxには基本となる3原則があり、そのルールに則ってコードを書いていく必要があります。
その前に、Reduxには大きく分けて3つの要素(Action, Store, Reducer)があることを確認しておきましょう。
Actionとは
Actionとは、簡単にいうと「アプリケーションから情報をstoreへ送るためのもの」。
Action Creatorと呼ばれる関数の戻り値にセットすることで使える。
// Action名の定義
const SEND = 'SEND';
// Action Creator
send(value) => {
// Action
return {
type: SEND,
value,
};
}
Actionはtypeプロパティを必ず持ち、typeプロパティの中の文字列からactionが発火しvalueがstoreへ送られる。
Storeとは
Storeとは、アプリケーションのstateを保持している場所のこと。
crateStore()メソッドを使って作成する。
また、Storeは以下のようなことをしてくれる。
- アプリケーションの状態(state)を保持する
- getState()メソッドを通してstateへのアクセスを許可する
- dispatch(action)メソッドを通して状態の更新を許可する
- subscribe(listener)メソッドを通してリスナーを登録する
- subscribe(listener)メソッドによって返された関数を通してリスナーの登録解除をハンドリングする
など。subscribeについてはちょっとよくわかってないけど、上2つのstateの保持とgetState()でstateへのアクセスに関しては通常のstateと変わらない仕様。
dispatch()メソッドの引数にAction Creatorを渡すことでActionがReducerに送られる。
Reducerとは
Reducerとは、Actionに呼応してアプリケーションの状態をどのように変化させるか指定するためのもの。
受け取ったActionのタイプ属性を見て、対応するActionの値を用いて、Storeのstateを更新する。
switch文を使ってActionの名前を判別して処理を書く。
function sample(state = initialState, action){
switch(action.type){
case SAMPLE_ACTION:
return Object.assign({}, state, {
...
}
)
case ...
}
}
ここで注意しなければならないことは、Object.assign()メソッドを使用してstateの中の配列を書き換えること。stateそのものを変更させてしまわないように注意!
また、以下のことをreducerの中ではやってはいけない。
- 引数のstate, actionインスタンスの値を変更すること
- 毎回値が変わるもの(
Date.now()やMath.random())を使うこと
とにかくreducerはactionで書き換えられるように指示されたもの以外は変えちゃいけないってことだな。
以上の3つの要素を頭に入れたうえで、基本三原則に則ってコードを書いていきます。
Reduxの基本三原則
- Single source of truth
アプリケーション全体のstateは一つのstoreの中のobjectツリーに格納される。
- State is read-only
actionを発火することが、stateを更新する唯一の方法。
- Changes are made with pure functions
stateがactionによってどのように変更されるか指定するために、純粋なreducerを書く。
以上がreduxの基本、って感じですね。これだけでも割と理解するまで時間がかかりますが、実際にやってみないとわからないんですよね。。頑張ります。
また、会社のコードをみて学んだことを書いていきます。
- types.jsを用いてactionの名前を管理する
上記のActionのコードではAction名をその場で宣言して使っていますがもちろん実務ではそんなことしないわけで、actionsディレクトリの中にtypes.jsというファイルを作成し、そこにaction名をすべて格納するようにしていた。
しかも、actionName()関数を作成し、引数に文字列を持ってきて組み合わせた文字列をreturnすることでAction名をいい感じに管理していた。
const actionName = (prefix, action) => {
return `@sample_app/${prefix}/${action}`;
};
- connect()()の意味
reduxにはconnect(func1, func2)(Test)といった関数がある。二つのカッコは一つ目のカッコを含めたconnect()の返り値が関数になっているため。
第一引数のfunc1はcomponentに渡すpropsが入っている。
第二引数のfunc2はreducerを呼び出して、reduxで管理しているstateを更新する。
Testは取得したデータをpropsとして扱いたいcomponentを指定する。
詳しいところは割愛するけど、export default connectをするとそのファイルの中で
this.props.~~~ でstateを使うことができる。
また、
第一引数のところは何もなければ下のように書く。
export default connect(
() => {},
{
exportAction: AppActions.exportedAction,
}
)(ExportAhead);
総括
reduxに関してはまあわかるんですが、これに加えてredux sagaという謎の代物が組み合わさってくるんです…redux sagaに関しても勉強して理解出来次第記事にしようかと思いますが、正直難しすぎてできる気がしねえ。でも実際に触れてみるとかわることもありそうだし勉強します。
あとReact Native Debuggerについても記事にしたいです。reduxはstateの居場所が見えなくなるので挙動の確認に必須だと感じたので。
あと割と本気でバックエンドの勉強をしようと思ってます。ただバックエンドに関してはフロントよりも勉強だけじゃどうにもならない部分があると思うので、実務でいつかやれるように…なりたい。
あと、アイカツスターズ1年目見終わって号泣しました。