Skip to content

Latest commit

 

History

History
 
 

9-redux

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

9 - Redux

本章では(おそらくここまでで最も難しい章なのですが)、アプリケーションにReduxを追加し、Reactと連携させます。Reduxはアプリケーションの状態を管理するもので、アプリの状態を表現する素のJavaScriptオブジェクトであるstore、一般的にユーザが起点となるaction、アクションハンドラにも見えるreducerが合わさったものです。reducerはアプリケーションの状態(store)に影響を及ぼし、アプリケーションの状態が変更がされると、アプリケーションに何かが起こります。Reduxの分かりやすい動くデモがここにあります。

Reduxを可能な限りシンプルに扱うにはどうすればよいか説明するため、アプリはメッセージとボタンで構成されるようにします。メッセージは犬が鳴いているかどうか(最初は鳴いていません)を伝え、ボタンを押すと犬が鳴き、メッセージが更新されるようにします。

ここでは、reduxreact-reduxの2つのパッケージが必要になります。

  • yarn add redux react-reduxを実行します。

はじめに、2つのフォルダ、src/client/actionssrc/client/reducersを作ります。

  • actions内に、以下のdog-actions.jsファイルを作ります:
export const MAKE_BARK = 'MAKE_BARK';

export const makeBark = () => ({
  type: MAKE_BARK,
  payload: true,
});

ここではアクションタイプMAKE_BARKを定義しています。また、MAKE_BARKアクションのトリガーとなる関数(これはaction creatorとも言います)makeBarkも定義します。どちらも他のファイルから利用するため、exportされています。このアクションはFlux Standard Actionモデルで実装されています。type属性とpayload属性を持っているのはそのためです。

  • reducersフォルダに以下のようなdog-reducer.jsファイルを作ります:
import { MAKE_BARK } from '../actions/dog-actions';

const initialState = {
  hasBarked: false,
};

const dogReducer = (state = initialState, action) => {
  switch (action.type) {
    case MAKE_BARK:
      return { hasBarked: action.payload };
    default:
      return state;
  }
};

export default dogReducer;

ここではアプリの初期状態として、hasBarkedプロパティがfalseになっている状態を定義しています。また、どのアクションが実行されたかによって状態を作る関数dogReducerも定義しています。この関数は状態を変更することがありません。代わりに新しい状態オブジェクトを返します。

  • storeを作るためapp.jsxを修正します。ファイルの中身全体を以下の内容に置き換えます:
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import dogReducer from './reducers/dog-reducer';
import BarkMessage from './containers/bark-message';
import BarkButton from './containers/bark-button';

const store = createStore(combineReducers({
  dog: dogReducer,
}));

ReactDOM.render(
  <Provider store={store}>
    <div>
      <BarkMessage />
      <BarkButton />
    </div>
  </Provider>
  , document.querySelector('.app')
);

見ると明らかなように、Reduxの関数createStoreがstoreを作ります。storeオブジェクトはReduxのcombineReducers関数を使って、reducerを全て(この例では1つだけですが)集めたものです。各reducerはここで名前がつけられます。ここではdogという名前をつけています。

ここは純粋なReduxの部分です。

それではreact-reduxを使ってReduxとReactを結びつけましょう。react-reduxがReactアプリにstoreを渡せるようにするため、アプリ全体を<Provider>コンポーネントで包みます。このコンポーネントは1つだけしか子要素を持てません。そのためここでは<div>要素を作り、この<div>要素にアプリの2つの重要な要素であるBarkMessageBarkButtonを持たせるようにします。

importセクションにある通り、BarkMessageBarkButtoncontainersフォルダからimportしたものです。ここはComponentsContainersという2つのコンセプトを紹介するよい機会です。

Component賢くない(dumb) Reactコンポーネントです。これはReduxの状態について何も知らないという意味です。Containers は *賢い(smart)なコンポーネントです。これは状態を知っており、他の賢くないコンポーネントに接続(connect)*できるためです。

  • src/client/componentssrc/client/containersの2つのフォルダを作ります。

  • componentsの中に、以下のファイルを作ります:

button.jsx

import React, { PropTypes } from 'react';

const Button = ({ action, actionLabel }) => <button onClick={action}>{actionLabel}</button>;

Button.propTypes = {
  action: PropTypes.func.isRequired,
  actionLabel: PropTypes.string.isRequired,
};

export default Button;

そして、message.jsx:

import React, { PropTypes } from 'react';

const Message = ({ message }) => <div>{message}</div>;

Message.propTypes = {
  message: PropTypes.string.isRequired,
};

export default Message;

これらは賢くないコンポーネントの例です。ロジックがなく、Reactのprops経由で問い合わせが来たものをそのまま返すだけのものです。button.jsxmessage.jsx の主な違いは、Buttonはそのプロパティとしてアクション(action) を持っていることです。アクションはonClickイベントに結び付けられています。アプリのコンテキストで、Buttonラベルは変化することがありませんが、Messageコンポーネントはアプリの状態を反映し、状態によって変化します。

繰り返しますが、 コンポーネント はReduxの アクション やアプリの状態 について何も知りません。そのため、適切なactionsdataを2つの賢くないコンポーネントに伝えるための賢いコンテナを作ることになるのです。

  • containers内に、以下のファイルを作ります:

bark-button.js

import { connect } from 'react-redux';
import Button from '../components/button';
import { makeBark } from '../actions/dog-actions';

const mapDispatchToProps = dispatch => ({
  action: () => { dispatch(makeBark()); },
  actionLabel: 'Bark',
});

export default connect(null, mapDispatchToProps)(Button);

そして bark-message.js:

import { connect } from 'react-redux';
import Message from '../components/message';

const mapStateToProps = state => ({
  message: state.dog.hasBarked ? 'The dog barked' : 'The dog did not bark',
});

export default connect(mapStateToProps)(Message);

BarkButtonButtonmakeBarkアクション、そしてReduxのdispatchメソッドを結びつけます。また、BarkMessageはアプリケーションの状態とMessageを結びつけます。状態が変更されると、Messageは自動的に適切なmessage属性を再描画します。これらはreact-reduxconnect関数によって動作します。

  • yarn startを実行し、index.htmlを開きます。そうすると、"The dog did not bark"とボタンが表示されます。ボタンをクリックすると、"The dog barked"というメッセージが表示されるはずです。

(原文: 9 - Redux)

次章 : 10 - Immutable JS と Redux の改良

前章 または 目次 に戻る。