概要
React + Redux のサンプルを使って、Reducer の作成と動作の確認をします。
準備
Action 編の続きに modal のクラスを追加したコード(tag/init_reducer
)から行います。
※ 実装完了はtag/reducer
メッセージダイアログを表示する Reducer の作成を行います。
Reducer とは
Reducer は現在の state と Action から、新しい state を生成します。
(previousState, action) => newState
Reducer 自体は function ですが、Reducer 名がそのまま state 名になります。
function errorMessage(state = null, action) {
:
return newState;
}
state : {
errorMessage: newState,
otherStates: ...
}
Reducer は新しい state を生成してください。 前の state を変更してはいけません。
function reducer(state = null, action) {
return Object.assign({},
state,
{
completed: true
});
}
Action はすべての Reducer に送られるため、関係のない Action の場合は現在の state を返してください。
function reducer(state = null, action) {
if (action.type != ACTION_A) {
return state;
}
:
return newState;
}
よく使うパターン
配列の追加
[...state.values, newValue]
配列のある要素の変更
[
...state.slice(0, action.index),
modifiedValue,
...state.slice(action.index + 1)
]
オブジェクトの変更
Object.assign({},
state,
{
completed: true,
name: "new name"
});
Reducer の作成
MessageModal
クラスは title
. message
, visibility
を持った modal
オブジェクトをとるので、表示するだけの Reducer を作ってみます。
function messageModal(state = null, action) {
return {
visibility: "show",
title: "Sample Modal",
message: "Lorem ipsum dolor sit amet, consectetur adipisicing elit,"
}
}
これを実行すると、何も起きませんが右のペーンを見ると、messageModal
state に title
. message
, visibility
が設定されていることがわかります。
ダイアログが表示できるように、containers/App.js
を修正し state を props に設定します。
import MessageModal from "../components/MessageModal.js"
:
render() {
const { children, inputValue, messageModal } = this.props;
return (
<div>
{this.renderErrorMessage()}
{this.renderSample()}
<MessageModal modal={messageModal} onPrimaryButton={() => {}}/>
{children}
</div>
);
}
:
function mapStateToProps(state) {
return {
messageModal: state.messageModal,
errorMessage: state.errorMessage,
inputValue: state.router.location.pathname.substring(1)
};
}
実行するとメッセージダイアログが表示されます。
Action による処理
Reducer が state を作ってダイアログが表示できるようになったので、今度は Action によって表示・非表示をコントロールできるようにします。
まず、Action を作成します。
export const SHOW_MODAL = "SHOW_MODAL";
export const HIDE_MODAL = "HIDE_MODAL";
export function showModal(title, message) {
return {
type: SHOW_MODAL,
title: title,
message: message
}
}
export function hideModal() {
return {
type: HIDE_MODAL
}
}
ダイアログはデフォルトでは非表示なので、初期値を次のようにします。
const messageModalInitial = {
visibility: "hide"
};
function messageModal(state = messageModalInitial, action) {
:
}
type
が SHOW_MODAL
, HIDE_MODAL
のときに新しい state を作ります。
function messageModal(state = messageModalInitial, action) {
const { type, title, message } = action;
switch (type) {
case ActionTypes.SHOW_MODAL:
return {
visibility: "show",
title: title,
message: message
};
case ActionTypes.HIDE_MODAL:
return {
visibility: "hide"
};
default:
return state;
}
関係のない action
に対しては何も行わないので、default
では現在の state
をそのまま返します。
ここで実行すると、初期状態が hide
なのでダイアログが表示されなくなります。また、右のペーンで visibility
が hide
になっていることが確認できます。
ボタンを追加して、showModal
を呼びます。
:
handleShowModal(e) {
const title = "Sample Modal";
const message = `Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`;
this.props.showModal(title, message);
e.preventDefault();
}
:
<button type="button" className="btn btn-primary btn-lg" onClick={::this.handleShowModal}>
show modal
</button>
show modal ボタンを押すと state
が更新されダイアログが表示されます。
同じように close ボタンで hideModal
が呼ばれるように修正します。
:
handleModalPrimaryButton(e) {
this.props.hideModal();
e.preventDefault();
}
:
<MessageModal modal={messageModal} onPrimaryButton={::this.handleModalPrimaryButton}/>
:
最後に
Reducer は state の形が決まっていれば実装は割と簡単だと思います。
ただ、Redux や flux では同じ state のときには同じ表示になることを意識する必要があり、UI の表示が決められるような state を設計するのが重要になります。
コンポーネントとかモジュールとかいうとメソッドが呼ばれてそ動くことが多かったので、state を中心にして state に従って UI に反映するというのは考え方を変えていかないといけないと感じました。