State 管理 の Redux を最近学び始めたので、そのメモ。
1:なぜ Redux が必要か?
State 管理 を 複数のコンポーネントでする場合、親コンポーネントから孫コンポーネントその下のひ孫コンポーネント...とコンポーネントが増えれば増えるほど Prop でデータを渡すことが多くなることがあります。
その場合の、データのバケツリレー(親コンポーネントからひ孫コンポーネントにデータを渡す場合の、息子・孫コンポーネントのProp渡し)を省略するために、Redux を使う。
Redux を使えば、一つの大きな State を、親コンポーネントからひ孫コンポーネント始めその下のコンポーネントまで、__1回の呼び出しでアクセスできる__ようにできる。フォームの細かい State など例外を除けば、この大きな State で状態を管理してみよう、というのが Redux。
※ 正確にコードを読んだわけでも Redux について熟練でいるわけでもないので、意訳や解釈が間違っている部分についてはご容赦ください。
2:Redux @ コード
ここでは、React のチュートリアルのコードで、Redux @ React の簡単な概要について説明します。
以下のサイトを参照しました。『Redux』を用いて状態管理をしてみよう!
1. 下準備
Redux を使う下準備に State を作る必要があります。以下のコードを src/index.js などに加えます。(※ reducers については後で説明します)
- createStore & Provider
import {createStore} from "redux"
import {Provider} from "react-redux"
import reducer from "reducers"
// 省略
const store = createStore(reducer)
//
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
これで、reducer のデータを参照した 大きな State が、作成され、Provider の子要素である App で参照できるようになります。
2. 大きな State のアクセス方法(書き込み)
アクセスには、読み出し と 書き込みがあります。ここでは、「簡単な読み出し」と「簡単な書き込み」を説明します。
- 簡単な読み出し
上のコードの store を持っている場合は、下のコマンドで store の中の State を取得できます。
console.log(store.getState())
簡単ですね。
- 簡単な書き込み (更新)
書き込みで必要になるのが、Action と Reducer になります。例えを使って意訳で言えば、__「Action は API の URL送信(とパラメーター)・Reducer は API内部のロジック」__になります。
Action と Reducer は、例えば下のようなファイルで書きます。
- Action
このファイルにある textChange を 呼び出すと、type が TEXTCHANGE である操作を Reducer から探してもらい、引数から取り出した textValue と textLength を引数として渡します。
API で言えば、type が URLで、(textValue, textLength)
がパラメーターの部分です。
export const TEXTCHANGE = "TEXTCHANGE"
export const textChange = (textValue, textLength) => {
return {
type: TEXTCHANGE,
textValue: textValue,
textLength: textLength,
};
};
どのようにアクセスするかというと store があるファイルからは、以下のようにしてアクセスできます。
import {addTodo} from "./actions"
//省略
let text_hoge = "hogehoge"
store.dispatch(textChange(text_hoge, text_hoge.length))
ですが、Action はあくまでも APIのURL入力だけのようなものだけなので、API内部のロジックが必要になります。それが Reducer です。
- Reducer
Reducer では、API の内部ロジックのようなものを作っていきます。
import {combineReducers} from 'redux';
import text from './text';
export default combineReducers({text});
このファイルの関数名「combineReducers」で、内部ロジックを作っている reducer ファイルをまとめています。なので、「src/reducers/text.js」にある内容がまとめられた前のものになります。
import {TEXTCHANGE} from '../actions';
const initialState = {textLength: 0, textValue: ''};
export default (state = initialState, action) => {
switch (action.type) {
case TEXTCHANGE:
return {textValue: action.textValue, textLength: action.textLength};
default:
return state;
}
};
action に、actions (APIのURLとパラメーターのようなもの) からの入力が入ります。ここでは、type で条件分岐して、どの内部ロジックの処理をするか分岐させています。
3. 読み出し
ここまでで、コマンド上での読み出しと書き込みに触れましたが、ここでは React のコンポーネント上からのアクセスについて触れます。
- 読み出し
読み出しをするには、読み出しが必要なファイルで、以下のような Funtion を作ります。
const mapStateToProps = state => {
return {
textValue: state.text.textValue,
textLength: state.text.textLength,
};
};
これで、関数名の意味のまま、上記の store.getState()
では state だった textValue と textLength の内容が、props に入ります。
また、書き込み をコンポーネントから行うために、以下のような Function を作ります。
const mapDispatchToProps = dispatch => {
return {
textChange: (textValue, textLength) =>
dispatch(textChange(textValue, textLength)),
};
};
dispatch は 関数コンポーネントで const hoge = ({dispatch}) => {
で取得して、利用することもできます。
4.まとめ
Redux は、Props のバケツリレーを避けるために、大きな State を管理してくれる。State の読み出しは、store を作成したファイルでは楽だが、そうでない場合は mapStateToProps
が必要で、書き込みには、dispatch が必要。