62
77

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ReactAdvent Calendar 2016

Day 5

ブラウザだけでできるReact・Reduxチュートリアル

Last updated at Posted at 2016-12-06

はじめに

 「React」はFacebookが公開している、ユーザーインタフェース(以下、UI)を効率的に構築することを目的としたJavaScriptライブラリです。

従来の一般的なWebアプリケーションだと、JavaScriptはJQueryなどのライブラリを使ってUIを生成していました。
ところが、従来のJavaScriptのライブラリで書かれたコードはJSのコードが大規模になるにつれてメンテナンスが難しくなるという欠点を持っていました。

それに対してReactは

  1. JS内にHTMLタグを埋め込むような記述ができ、「アプリケーションがどのように見えるか」を単純に表現できる
  2. データに変更があるときには更新の必要があるコンポーネントだけ更新する
  3. コンポーネントという単位でUIを管理することで複雑なUIでもUIを再利用したりテストしやすくする

といった特徴を持つことで、複雑なUIを作成するときでもコードのメンテナンスが容易です。
さらに、VirtualDOMという内部の仕組みを持つことで表示速度も速いため、多くのエンジニアに受け入れられつつあります。

とても便利な反面、今までのJQueryなどによるUIの生成とは勝手が違うので初めてReactを触る方は戸惑うことも多いとおもいます。
というより、Reactを触ったことがない人は上の文章だけ読んでもなんのこっちゃとなってしまうかとおもいます。

しかし、実際にReactを触ろうとするとReactを書くならES2015で書かなきゃ!とかトランスパイラ?Babel?ビルドツールはWebpackがbrowserify?なにそれおいしいの?となって挫折してしまう人も多いのではないでしょうか。

そこで今回はサーバーやビルドツールなどの面倒な環境構築ツール無しでReactによるUI構築を体験出来る環境を用意しました。
この環境で簡単なUIを作ってみることでReactの基本的な使い方を理解してもらえればいいなと思います。

なお、今回はReactの基本的な使い方を学ぶことに集中してもらうため、ES2015やES2016の機能は原則使用しません。
本当にReact初心者、JS初級者の人にはReact + ES2015は敷居が高いと考えるからです。
もし興味がある人はちまたに優れた資料や書籍が増えてきたので、そちらを参考にしてください。

ES2015系の参考文献
http://qiita.com/mizchi/items/3bbb3f466a3b5011b509
https://liginc.co.jp/series/es6

ここまで読んで、もっと本格的にReact.jsやES2015に入門したいという方は下記の記事がオススメです。

ゼロから始めるJavaScript生活
http://qiita.com/takahashim/items/7838334d1451fb0a9811

想定読者(期待するスキル)

  • HTML,CSS,JSによって何らかのWebアプリケーションを構築した経験がある

要求環境

  • インターネットに接続できる(CDNで必要なライブラリを取得するため)

チュートリアル本編

Reactを使って簡単なUIを作る

テンプレートHTMLの用意

まずは簡単なHTMLをReactで生成してみましょう。
まずはHTMLを用意します。
今回は複雑なビルド環境などを用意せずに作成するため、
必要なjsのライブラリをscriptタグで読み込んでいます。
それぞれのライブラリの役割は下記の通りです。

  • react.js → Reactのコアライブラリ
  • react-dom.js → Reactを使ってHTMLを生成する時に使用するライブラリ
  • babel-standalone.js → ブラウザ単独でJSX(後述)を使用するためのライブラリ

react.jsとreact-dom.jsは歴史的には1つのreact.jsというライブラリでしたが、
ReactでiOSやAndroidの開発を可能にするReactNativeが登場すると、
Reactとしての基本部分と動作環境(Webかネイティブか)に依存した部分を分ける必要が生じ、
DOMの描画に関する部分はreact.jsからreact-dom.jsに切り出されたという経緯があります。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>test</title>
  </head>
  <body>
    <div id="content"></div>
    <script src="https://unpkg.com/react@15/dist/react.js"></script>
    <script src="https://unpkg.com/react-dom@15/dist/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.2/react-redux.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.19.0/babel.min.js"></script>
    <script type="text/babel">
      // コンポーネントの定義

      var helloReact = <div>Hello! React!</div>;
      var content = document.getElementById('content');
      ReactDOM.render(helloReact, content);
    </script>
  </body>
</html>

大事なのは下の部分です。

var helloReact = <div>Hello! React!</div>;
var content = document.getElementById('content');
ReactDOM.render(helloReact, content);

ReactではこのようにJS内に表示したいHTMLの要素を埋め込むような形で表現したいUIを作成します。

JSの中にHTMLを埋め込むような不思議な記述の仕方は純正のJSの構文ではありません。
この構文はJSXと呼ばれるJavaScriptにXMLのような構文を追加する言語拡張です。JSXを使うと、JavaScriptコード中にHTMLタグを埋め込んでいるかのように記述できます。

通常はJSXを使う場合は前もってJSXで書かれた部分をブラウザで実行可能な形に変換する処理が必要となります。
しかし今回はそういった大変な準備をしないでもReactを触れる環境を作ることに主眼を置くため、
babel-standalone.jsというものを使用することでhtml単独でJSXを使用可能としています。

ReactDOM.renderはHTMLを生成して、所定の位置に埋め込むための関数です。
ReactDOM.renderは2つの引数を取ります。

第1引数はコンポーネントからつくられるHTMLの要素
第2引数 HTML要素を埋め込むページのHTML中の場所

となっています。

つまりこのコードは<div>Hello! React!</div>というHTMLをcontentというidを持つ要素の中に埋め込むという処理を行っていることになります。

これからこのコードを拡張してカウンターを作成していきますが、これ以降すべてのコードはタグ内に記述することを前提に説明を行います。

クラスをつける

次にCSSクラスをつけてみましょう。

style.css
.text {
  color: red;
}

Reactで生成したHTMLにCSSのクラスを適用したい場合は、
classではなく、classNameという名前でクラス名を指定してあげる必要があります。
これはclassと言うのがJSの予約語だからです。
先ほど用意したstyle.cssをhtmlに読み込んで、divのclassNameプロパティにクラス名を設定すれば、
Hello JS!の文字が赤くなっていることを確認できるはずです。

var helloReact = <div className="text">Hello! JS!</div>;
var content = document.getElementById('content');
ReactDOM.render(helloReact, content);

コンポーネント化、JSX内でのJSの評価

もう少し複雑なUIを生成する

次に、もう少し複雑なHTMLを作ってみましょう。
カウンターの雛形になる部分です。

var stepCount = (
  <div>
    <h3>
      りんごの個数
    </h3>
    <button>
      プラス
    </button>
    <div>0</div>
    <button>
      マイナス
    </button>
  </div>
);
var content = document.getElementById('content');
ReactDOM.render(stepCount, content);

このように少し複雑なUIでも、Reactは一つの変数にまとめて描画することが可能です。

UIにJSの変数の中身を埋め込む

このままだとりんごはずっと0個の表示のままなので、
変数に格納した値をHTMLに埋め込めるようにします。

まずはJSの変数の内容を画面に表示できるようにコードを修正します。

これはJSXの中でJSを評価した結果を出力させることで実現することができます。
JSXの中でJSを実行したい場合は中括弧{}でJSで評価したい内容を囲ってあげます。
今回はcountの変数の中身を表示したいので{count}と書きます

数値の埋め込み
var count = 5;
var stepCount = (
  <div>
    <h3>
      りんごの個数
    </h3>
    <button>
      プラス
    </button>
    <div>{count}</div>
    <button>
      マイナス
    </button>
  </div>
);
var content = document.getElementById('content');
ReactDOM.render(stepCount, content);

これで個数の部分には5個と表示されるようになります。

カウンターをコンポーネント化する

いろいろ作ろうとすると、同じようなHTMLを何度も繰り返し使わなければならないことがあります。
今はリンゴだけですが、みかんやバナナの個数を表示したい、という場合も出てくるかもしれません。
名前や個数が違うだけの、ほぼ同じHTMLを何度も書くのは大変なので、使いまわせる部分を共通化します。
今回は個数を数えるものの名前と、表示する個数をHTMLを作るときに決めることができる部品を作ります。

これはReactの持つコンポーネント化という機能を使うことで実現できます。
コンポーネントはオブジェクト指向プログラミングでおけるクラスのようなもので、
使い回しが効くようなUIやUIに関わる機能をカプセル化することができる機能です。
コンポーネントはJSXに他のHTMLタグと同じように埋め込むことで『実体化』することができます。

カウンターをコンポーネント化
var Counter = React.createClass({
  render() {
    return (
      <div>
        <h3>
          {this.props.name}の個数
        </h3>
        <button>
          プラス
        </button>
        <div>{this.props.count}</div>
        <button>
          マイナス
        </button>
      </div>
    );
  }
});

var counters = (
  <div>
    <Counter name="りんご" count={3}/>
  </div>
);

var content = document.getElementById('content');
ReactDOM.render(counters, content);

Counter変数に入っているのがコンポーネントです。
React.createClassはコンポーネントを作成するための関数で、引数にはオブジェクトを渡す必要があります。
引数のオブジェクトのrenderメンバに設定されている関数はこのCounterコンポーネントから
UIを生成するときに呼ばれる関数です。
この関数が返しているJSXの部分がこのコンポーネントからUIを生成するときのUIの雛形となります。

先ほども書きましたが、コンポーネントはJSXを書くときに他のHTMLタグと同じように使うことができます。
名前や個数を設定したいときは、コンポーネントのプロパティ(props)という機能を使います。
プロパティはコンポーネントに外部から与えられるオプションのようなもので、HTMLタグで言うタグ名の後に与える属性と同じような形で設定してあげることができます。

今回のコードでいうとname="りんご"count={3}の部分です。
渡された値は、コンポーネント内でthis.props.(属性名)で参照することができます。

りんごだけでなく、みかんのカウンターも増やしたい場合は、
Counterコンポーネントからみかん用のエレメントを作る記述を追加してあげるだけでOKです。

みかんのカウンターも増やす場合
var Counter = React.createClass({
  render: function() {
    return (
      <div>
        <h3>
          {this.props.name}の個数
        </h3>
        <button>
          プラス
        </button>
        <div>{this.props.count}</div>
        <button>
          マイナス
        </button>
      </div>
    );
  }
});

var counters = (
  <div>
    <Counter name="りんご" count={3}/>
    <Counter name="みかん" count={4}/>
  </div>
);

var content = document.getElementById('content');
ReactDOM.render(counters, content);

カウンターの数値を変えることができるようにする

個数をpropsからstateによる管理へ変更する

このままだと増やしたり減らしたりすることができないので、
ボタンを押すと個数が増えたり減ったりする機能を追加します。
Reactでは画面の操作から書き換えられる情報を「状態(ステート)」というものを使って管理します。
ステートとは、コンポーネント内部で持てる変数のようなものです。
コンポーネントが実体化された時に初期化され、ユーザーの操作の結果などのコンポーネントの状態の変化を保持するために使われます。

状態が変更されると、変更があった部分をReactが自動で検知して、もう一度現在の状態にあった形で
HTMLを再生成してくれます。

まずは、個数を増やしたり減らしたりする機能の追加は後回しにして、
今までCounterコンポーネントを呼び出すときに属性として渡していた個数を
Counterエレメントの中で持つ状態として書き直します。

個数を状態として管理する
var Counter = React.createClass({
  getInitialState: function() {
    return {count: 0};
  },

  render: function() {
    return (
      <div>
        <h3>
          {this.props.name}の個数
        </h3>
        <button>
          プラス
        </button>
        <div>{this.state.count}</div>
        <button>
          マイナス
        </button>
      </div>
    );
  }
})

var counters = (
  <div>
    <Counter name="りんご"/>
  </div>
);

var content = document.getElementById('content');
ReactDOM.render(counters, content);

ボタンを押すと個数が増減するようにする

次に、ボタンをクリックしたときに状態を書き換える処理を追加します。

個数を足したり減らしたりする
var Counter = React.createClass({
  getInitialState: function() {
    return {count: 0};
  },

  handlePlus: function() {
    this.setState({
      count: this.state.count + 1
    });
  },

  handleMinus: function() {
    this.setState({
      count: this.state.count - 1
    });
  },

  render: function() {
    return (
      <div>
        <h3>
          {this.props.name}の個数
        </h3>
        <button onClick={this.handlePlus}>
          プラス
        </button>
        <div>{this.state.count}</div>
        <button onClick={this.handleMinus}>
          マイナス
        </button>
      </div>
    );
  }
})

var counters = (
  <div>
    <Counter name="りんご"/>
  </div>
);

var content = document.getElementById('content');
ReactDOM.render(counters, content);

プラスボタン、マイナスボタンをクリックしたときに起動される関数を登録してあげます。
JSXのHTMLの部品には通常のHTMLと同様にonClickなどのイベントハンドラを登録することができます。

ボタンクリック時に実行されるそれぞれの関数の中ではsetStateという関数を実行します。

setStateは文字通りコンポーネント内の状態を書き換えるための関数です。
引数にオブジェクトをとり渡されたオブジェクトのメンバ名と同じメンバ名のステートが存在した場合はそのステートを書き換えます。

setStateでstateが変わると、Reactは自動的にもう一度render関数を実行します。
この時、this.state.countは変更されているはずなので、実際に生成される個数も変更されるという仕組みです。

Reduxと結合する

次に、今まで作ってきたReactのコンポーネントとReduxを結合してみます。
Reduxとは、Fluxアーキテクチャと呼ばれるものの実装の一つでReactを使ったフレームワークのことです。

Fluxはより高度で大規模なシングルページアプリケーションを作る時に、複雑化しすぎてアプリが破綻するのを避け、長期的にメンテナンスし続けることを可能にするためのアーキテクチャです。

Reduxは大きく分けてActions、Reducers、Store、Viewの4つの構成要素から構成されています。
このうちViewとは実際にUIを生成する機能を持つ部分で、Reactが担当します。

Reduxは処理が進む方向が必ず1方向で、Actions -> Reducers -> Store -> Viewの順にコードが実行されます。

また、大きな特徴として次の3原則を提示しています。

Single source of truth

アプリケーションの状態を表すデータをアプリのあちらこちらで管理したり、重複して管理してしまうことを防ぐため、アプリで保持すべき状態を一つの場所に集約する環境を作ろう、という考え方です。

こうすることで、アプリの状態(このボタンは見えてるか?といったフラグ管理から、先ほどのカウンタコンポーネントでコンポーネントに持たせていたstateまで、ユーザーの操作やAPIの連携結果などによって変更される全てのデータ)を見るためには一つの場所を見に行ったり書き換えたりすれば良いという状況にでき、アプリケーションの状態管理の見通しが良くなります。

Reduxではアプリケーションの状態は全てStoreが持っているstateという1個のオブジェクトの中でまとめて管理します。

state is read-only

Storeが管理しているアプリケーションの状態はViewから直接書き換えに行くことはできません。
Viewから状態を書き換えたいときは必ずアクション(ただのJSオブジェクトで表現されます)というものを発行しなければなりません。

Reduxによって状態の変更はアクションが発行された順番に一つづつ行われるため、状態を変化させる順番を厳密に決めることができます。また、アクションはただのJSオブジェクトなのでデバック用にロギングしたり、後でデバッグのために再現したりすることが比較的簡単です。

Changes are made with pure functions

Actionにより状態をどう変更させるかはReducerという部分が行ないます。
この時Reducerは現在の状態とアクションを受け取って新しい状態オブジェクトを返却する純粋な関数でなければいけません(副作用はつけてはいけない!)。

それでは、サンプルコードを記載した後にそれぞれの要素について解説していきたいと思います。

Reduxと結合する
    // 初期状態の設定とreducerを作成する部分
    var initialFruit  = {
      name: "りんご",
      price: 300,
      count: 0
    };
    var fruit = function(state, action) {
      if (!state) {
        // stateが初期化されていない場合は、initialFruitを最初の状態として初期化する
        state = initialFruit;
        return state;
      }

      switch (action.type) {
        // ② store.dispatchで伝播されたactionはこのswitch節に入ってくる
        // typeプロパティの値別に判定を行う
        case 'INCREMENT':
          // typeプロパティが'INCREMENT'ならcountを1増やす
          return {
            name: "りんご",
            price: 300,
            count: state.count + 1
          };
        case 'DECREMENT':
          // typeプロパティが'DECREMENT'ならcountを1減らす
          return {
            name: "りんご",
            price: 300,
            count: state.count - 1
          };
        default:
          return state;
      }
    };
    // storeの生成はRedux.createStoreが勝手にやってくれる
    var store = Redux.createStore(fruit);

    // Viewの部分
    var Counter = React.createClass({
      handlePlus: function() {
        // ① 用意したactionをreducerに伝播
        var incrementAction = {type: "INCREMENT"};
        store.dispatch(incrementAction);
      },
      handleMinus: function() {
        // ① 用意したactionをreducerに伝播
        var decrementAction = {type: "DECREMENT"};
        store.dispatch(decrementAction);
      },
      render: function() {
        return (
          <div>
            <h3>
              {this.props.name}の個数
            </h3>
            <button onClick={this.handlePlus}>
              プラス
            </button>
            <div>{this.props.count}</div>
            <div>{this.props.count * this.props.price}</div>
            <button onClick={this.handleMinus}>
              マイナス
            </button>
          </div>
        );
      }
    })

    // ViewとStoreで管理しているstateの糊付けを行う部分
    var mapStateToProps = function(state) {
      return {
        // stateのnameプロパティをCounterコンポーネントのthis.props.nameにセットする
        name: state.name,
        // stateのpriceプロパティをCounterコンポーネントのthis.props.priceにセットする
        price: state.price,
        // stateのcountプロパティをCounterコンポーネントのthis.props.countにセットする
        count: state.count
      };
    };
    var connect = ReactRedux.connect;
    var CounterContainer = connect(mapStateToProps)(Counter);

    var Provider = ReactRedux.Provider;
    var counters = (
      <Provider store={store}>
        <CounterContainer/>
      </Provider>
    );

    var content = document.getElementById('content');
    ReactDOM.render(counters, content);

Actions

アクションはアプリケーションの状態を書き換えるためにReducerに送るデータの塊です。
アクションはtypeというメンバを持つオブジェクトの形式で表現されます。
他のメンバを持足せるかどうかは開発者の自由です。

      handlePlus: function() {
        // ① 用意したactionをreducerに伝播
        var incrementAction = {type: "INCREMENT"};
        store.dispatch(incrementAction);
      },

プラスボタンをクリックした時に作られているincrementActionがアクションです。
incrementAction自体は何の変哲も無いオブジェクトですので、これをReducerに送る処理が必要です。
Reducerに送る処理を行っているのがstore.dispatch関数です。
store.dispatch関数に渡されたアクションは全てreducerに渡されます。

actionについてさらに知りたい方はこちらをご覧ください。
http://qiita.com/kiita312/items/8f8d047e5cbd87399ccb

Reducers

「Reducer」は、Actionに呼応してアプリケーションの状態をどのように変化させるか指定します。受け取ったアクションのtypeメンバの中身に応じて状態を更新します。
今回のコードではfruit変数に入っている部分がreducerに相当します。

さらに詳しく知りたい方はこちらがおすすめです
http://qiita.com/kiita312/items/7fdce94912d6d9c801f8

    var fruit = function(state, action) {
      if (!state) {
        // stateが初期化されていない場合は、initialFruitを最初の状態として初期化する
        state = initialFruit;
        return state;
      }

      switch (action.type) {
        // ② store.dispatchで伝播されたactionはこのswitch節に入ってくる
        // typeプロパティの値別に判定を行う
        case 'INCREMENT':
          // typeプロパティが'INCREMENT'ならcountを1増やす
          return {
            name: "りんご",
            price: 300,
            count: state.count + 1
          };
        case 'DECREMENT':
          // typeプロパティが'DECREMENT'ならcountを1減らす
          return {
            name: "りんご",
            price: 300,
            count: state.count - 1
          };
        default:
          return state;
      }
    };

fruit変数内にはstore.dispatch関数でアクションが渡されてきた時に実行される関数が格納されています。
この関数は引数として現在のアプリケーションの状態と、store.dispatch関数から渡されてきたアクションを受け取ります。基本的にはこの2つの引数の情報を使って新しい状態オブジェクトを返却すると、それがアプリケーションの状態として使用されるようになります。

関数の最初の部分で、stateを初期化しています。一番最初はreducerの関数に渡されてくるstateが未定義(undefined)である可能性があるためです。

続いて、ここがreducerの肝となる部分ですが、渡されたactionのtypeメンバの中身に応じて、新しい状態を作成する処理を実行します。

例えば、typeメンバが'INCREMENT'ならstateのcountメンバを1増やしてオブジェクトを返す、といった具合です。

Store

Storeはアプリケーションの状態を保持し、状態が変更されたらViewにその変更を通知する役割を持つ部分です。
実はStoreを作るために書かなければならないコードはほとんどありません。
実は下記のコードだけです。

// storeの生成はRedux.createStoreが勝手にやってくれる
var store = Redux.createStore(fruit);

ReduxにはcreateStoreという関数があり、createStoreに使用するreducer(今回はfruit)を渡してあげれば、それだけで自動的にstoreを作ってくれるからです。

View

    // Viewの部分
    var Counter = React.createClass({
      handlePlus: function() {
        // ① 用意したactionをreducerに伝播
        var incrementAction = {type: "INCREMENT"};
        store.dispatch(incrementAction);
      },
      handleMinus: function() {
        // ① 用意したactionをreducerに伝播
        var decrementAction = {type: "DECREMENT"};
        store.dispatch(decrementAction);
      },
      render: function() {
        return (
          <div>
            <h3>
              {this.props.name}の個数
            </h3>
            <button onClick={this.handlePlus}>
              プラス!
            </button>
            <div>{this.props.count}個</div>
            <div>{this.props.count * this.props.price}円</div>
            <button onClick={this.handleMinus}>
              マイナス!
            </button>
          </div>
        );
      }
    });

    // ViewとStoreで管理しているstateの糊付けを行う部分
    var mapStateToProps = function(state) {
      return {
        // stateのnameプロパティをCounterコンポーネントのthis.props.nameにセットする
        name: state.name,
        // stateのpriceプロパティをCounterコンポーネントのthis.props.priceにセットする
        price: state.price,
        // stateのcountプロパティをCounterコンポーネントのthis.props.countにセットする
        count: state.count
      };
    };
    var connect = ReactRedux.connect;
    var CounterContainer = connect(mapStateToProps)(Counter);

    var Provider = ReactRedux.Provider;
    var counters = (
      <Provider store={store}>
        <CounterContainer/>
      </Provider>
    );

この部分は今まで作ってきたReact.jsのコンポーネントが担当します。
大きく変わっているのは2点です。

Reactのコンポーネントでは状態を持たない(this.stateは使わない)

Reduxを使う場合は原則としてアプリケーションの状態は全てStoreで管理します。
ですので、CounterコンポーネントはStoreから値を受け取って、その値を元にDOMを生成するだけの、状態の持たないコンポーネントになっています(ステートレスコンポーネントと言います)。

    var Counter = React.createClass({
      handlePlus: function() {
        // ① 用意したactionをreducerに伝播
        var incrementAction = {type: "INCREMENT"};
        store.dispatch(incrementAction);
      },
      handleMinus: function() {
        // ① 用意したactionをreducerに伝播
        var decrementAction = {type: "DECREMENT"};
        store.dispatch(decrementAction);
      },
      render: function() {
        return (
          <div>
            <h3>
              {this.props.name}の個数
            </h3>
            <button onClick={this.handlePlus}>
              プラス!
            </button>
            <div>{this.props.count}個</div>
            <div>{this.props.count * this.props.price}円</div>
            <button onClick={this.handleMinus}>
              マイナス!
            </button>
          </div>
        );
      }
    });

Counterコンポーネントからstateがなくなっているのがおわかりいただけるかと思います。

Storeが持っている状態をコンポーネントと結合する部分を追加する

コンポーネントはステートレスなものに書き換えたため、Storeの状態をコンポーネントに結合する部分を作る必要があります。

ReduxはStoreの状態をコンポーネントと結合する方法も提供しています。
それがReactRedux.connect関数です。

    // ViewとStoreで管理しているstateの糊付けを行う部分
    var mapStateToProps = function(state) {
      return {
        // stateのnameプロパティをCounterコンポーネントのthis.props.nameにセットする
        name: state.name,
        // stateのpriceプロパティをCounterコンポーネントのthis.props.priceにセットする
        price: state.price,
        // stateのcountプロパティをCounterコンポーネントのthis.props.countにセットする
        count: state.count
      };
    };
    var connect = ReactRedux.connect;
    var CounterContainer = connect(mapStateToProps)(Counter);

    var Provider = ReactRedux.Provider;
    var counters = (
      <Provider store={store}>
        <CounterContainer/>
      </Provider>
    );

connect関数は大変初見殺しなやつなのですが、主に以下の点を覚えていただければ十分かと思います。

・画面に表示する内容はCounterコンポーネントと全く同じ
・connectはCounterコンポーネントにStoreで状態の変更が起こった時に、状態オブジェクトからCounterコンポーネントがデータを表示するために必要なデータをpropsとしてCounterに渡してあげる(mapStateToPropsがstateオブジェクトのどの部分をCounterコンポーネントに渡すかを設定している部分)

また、このようにReduxのStateと結合するコンポーネントはコンテナと呼ばれます。

コンテナの上位にあるProviderはReduxが提供しているコンポーネントです。
始めのうちはとりあえず先ほど作ったstoreを持たせて全てのコンポーネントの一番上の親コンポーネントとして設置するおまじないだと思っていてくれれば十分です。

ここら辺は本当にわかりにくいので、さらに詳しく理解したい方はこちらをご覧ください。
http://qiita.com/kuy/items/869aeb7b403ea7a8fd8a#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%81%A8%E5%BD%B9%E5%89%B2

終わりに

以上でReactとReduxのチュートリアルを終わります。
ReactだけならまだしもReduxも入ってくると、最初のうちは何書いているかわかんないけどとりあえず写経しようという状態になることもしばしばあるかと思います。
ですがだんだん慣れてくると複雑なこともできるようになりますし、大規模なアプリケーションでもしっかりと破綻なく設計することができてきます。

このチュートリアルを通じてみなさんが少しでもReactへの理解を深めてもらえれば、それ以上の幸いはありません。

それでは皆さん、良い開発を!

62
77
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
62
77

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?