Reduxのデータの流れ
はじめに
最近youtubeでのreduxチュートリアルを一周したのですが、まだ理解が及ばないところが多いので、復習としてまとめていきます。
※取り組んだチュートリアルはこちら
Reduxとは
アプリケーションの状態(React.jsでのstate)を管理するライブラリ。
fluxフローという設計思想を元に作られています。
stateを一元管理できるので、各コンポーネントから直接データを参照・取得することができます。
fluxフローとは
アプリの設計思想の1つで、下記図のようにデータが常に1方向に流れる特徴があります。
View → Action → Dispatcher → Store → View・・・ の流れでユーザーの操作に伴い、画面が更新されていく仕組みです。
※Reduxはあくまでfluxフローを元に作られたものなので、fluxフローとはいくつか違う点(Dispatcherが無いなど)があります。
各項目について
View : ブラウザに表示されるアプリの各component(厳密にはブラウザに表示されるstoreのデータ)ユーザーが変更することで次のActionを飛ばすトリガーになる
Action : アプリの状態を変更する指示の内容
Dispatcher:Actionの内容をStoreに伝達する
Store: アプリの状態を保持しており、変更指示を受けたら該当データを更新する
Reduxのデータの流れについて
上記のfluxフローを踏まえて、reduxのデータの流れを見てみます。
今回はサインイン画面でサインインする場合を想定しました。
※あくまでデータの流れを理解するのが目的のため、実装方法やディレクトリ構造は簡略化しています。
流れだけ先に図にすると下記のようになります。
1.画面からユーザーが操作を実行
サインイン画面でユーザーがアカウント情報を入力&サインインボタンをクリック
関数名などは後述しますが、ひとまずボタンのDOMは下記のようになっています。
<button type="button" onClick={()=>dispatch(signInAction)}>サインイン</button>
2.クリックをトリガーにActionが発行される
Actionはアプリの状態を変更する指示の内容を必ずプレーンなオブジェクトで返します。
返すだけなので、Action自体に何かを変更する機能はありません。
中身は下記のイメージです。
export const SIGN_IN = 'SIGN_IN';
export const signInAction = () => {
return {
type: SIGN_IN,
payload: {
isSignedIn: true
}
}
}
Type:このActionを識別するための任意の文字列(今回はそのままSIGN_IN)
Payload:このActionを実行するために必要な任意のデータ(サインインさせたいので、trueのisSignInフラグを渡します。)
3.DispatchがActionを運ぶ
1のDOMクリック時に発火する関数内にsignInAction
を引数に持ったdispatch
がいます。
このdispatchによってactionが次のreducerへ渡されます。
4.ActionがReducerに渡される
Actionの内容を元に、変更された結果のstateを返してくれます。
下記では2種類の変数がありますが、上のinitialStateがデフォルトのstateを定義しています。デフォルトではログインされていない状態なので、フラグをfalseで持っておきます。
次にusersReducerは初期状態と先程のactionを受け、対応する状態を返してくれる関数です。
switch分で分岐されているので、SIGN_INのactionを受けたら対応のオブジェクトを返します。
import * as Actions from './Action';
// デフォルトのstate(ログインしていない状態)
const initialState = {
isSignedIn: false
}
export const usersReducer = (state = initialState, action) => {
switch (action.type) {
case Actions.SIGN_IN :
return {
...state,
...action.payload
}
default:
return state
}
}
ちなみにオブジェクトがスプレッド構文で書かれているのは、初期のstateとactionの値とまとめるためです。
今回はisSignInしかキーがないので、まとめられた結果、initialState側のisSignedInがtrueに上書きされます。
5.ReducerによりStore内のstateが変更される
ストアの中身は下記のイメージです。
configureStore
モジュールをimportし、定義したreducerを下記のように渡して登録しておくと、storeもReducerでの変更を受け取ってくれます。
import { configureStore } from '@reduxjs/toolkit';
import { usersReducer } from './Reducer.js';
export const store = configureStore({
reducer:{
users: usersReducer,
}
})
6.view側にstateが共有される
これで変更の更新はstoreに伝わり、最後view側に更新が伝わります。
下記ソース内のProvider
はラップしたコンポーネントにstoreの情報を渡す役割があります。
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { store } from './Store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Discussion