LoginSignup
22
22

More than 5 years have passed since last update.

React Tutorial Example (Redux)

Last updated at Posted at 2016-06-13

ReactFlux のフレームワークで利用すると効果的です。
ReduxFlux を参考に 3つの原則 を強調したフレームワークです。
前回 のアプリケーションに Redux を追加してみましょう。

Learning

  • Redux の Action, Reducer, StoreData Flow を利用する。
  • React と Redux で連携 connect を利用する。

Environment

  • node: v4.4.5
  • npm: v3.9.6

Comment Box Form

  • 完成される Source Code のファイルリストです。
$ tree -a -I node_modules
.
├── .babelrc
├── app.js
├── index.html
├── index.js
├── package.json
├── style.css
└── webpack.config.js

Let's hands-on

Setup application

  • git clone コマンドでアプリケーションをダウンロードします。
  • npm install コマンドで依存するモジュールをインストールします。
$ git clone https://github.com/ogom/react-comment-box-example.git
$ cd react-comment-box-example
$ git checkout react
$ npm install

Start HTTP Server

  • npm start コマンドで Webアプリケーション を実行します。
  • ブラウザで http://localhost:4000 をロードすると Comment Box Example が表示されます。
$ npm start
$ open http://localhost:4000

(API Server は React Tutorial Example (Express) をご利用ください。)

Add Redux package

  • Redux のモジュールをインストールします。
$ npm install redux --save-dev

Add Redux

  • createStore()Reducer を設定して Store を作成します。
    • store.dispatch()Acstion を実行すると State が変更されます。
index.js
+var Redux = require('redux');
+var createStore = Redux.createStore;
+var store = createStore(function(state, action) {
+  if (state === undefined) {
+    return [];
+  }
+
+  switch (action.type) {
+  case 'show_comments':
+    return action.comments;
+  case 'add_comment':
+    return state.concat([action.comment]);
+  default:
+    return state;
+  }
+});
+store.subscribe(function () {
+  return console.log(store.getState());
+});
+store.dispatch({type: 'show_comments', comments: data});
+store.dispatch({type: 'add_comment', comment: {author: "foo", text: "*bar*"}});
  • store.getState()console.log で出力すると State を確認することができます。

redux_comment

Add React Redux package

  • ReactRedux のモジュールをインストールします。
$ npm install react-redux --save-dev

Add Provider

  • Providerstore を設定して ReactRedux を連携します。
index.js
-var data = [
-  {id: 1, author: "Pete Hunt", text: "This is one comment"},
-  {id: 2, author: "Jordan Walke", text: "This is *another* comment"}
-];
-
-store.subscribe(function () {
-  return console.log(store.getState());
-});
-store.dispatch({type: 'show_comments', comments: data});
-store.dispatch({type: 'add_comment', comment: {author: "foo", text: "*bar*"}});
+
+var ReactRedux = require('react-redux');
+var Provider = ReactRedux.Provider;

 ReactDOM.render(
-  <CommentBox url="http://localhost:3000/api/comments" pollInterval={2000} />,
+  <Provider store={store}>
+    <CommentBox url="http://localhost:3000/api/comments" pollInterval={2000} />
+  </Provider>,
   document.getElementById('content')
 );

Add Connect

  • mapStateToPropsstate をマッピングします。
  • mapDispatchToPropsdispatch をマッピングします。
  • connect() でマッピングとコンポーネントを接続します。
app.js
-module.exports = CommentBox;
+var ReactRedux = require('react-redux');
+var connect = ReactRedux.connect;
+
+var mapStateToProps = function(state) {
+  return {data: state};
+};
+
+var mapDispatchToProps = function(dispatch) {
+  return {
+    showComments: function(comments) {
+      dispatch({type: 'show_comments', comments: comments});
+    },
+    addComment: function(comment) {
+      dispatch({type: 'add_comment', comment: comment});
+    }
+  };
+};
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(CommentBox);

Change Show Comments

  • successthis.setStatethis.props.showComments に置き換えます。
  • renderthis.state.datathis.props.data に置き換えます。
app.js
 var CommentBox = React.createClass({
   loadCommentsFromServer: function() {
     $.ajax({
       url: this.props.url,
       dataType: 'json',
       cache: false,
       success: function(data) {
-        this.setState({data: data});
+        this.props.showComments(data);
       }.bind(this),
       error: function(xhr, status, err) {
         console.error(this.props.url, status, err.toString());
       }.bind(this)
     });
   },
   render: function() {
     return (
       <div className="commentBox">
         <h1>Comments</h1>
-        <CommentList data={this.state.data} />
+        <CommentList data={this.props.data} />
         <CommentForm onCommentSubmit={this.handleCommentSubmit} />
       </div>
     );
   }
 });

Change Add Comment

  • newCommentsthis.setStatethis.props.addComment に置き換えます。
  • successthis.setStatethis.props.showComments に置き換えます。
  • errorthis.setStatethis.props.showComments に置き換えます。
app.js
 var CommentBox = React.createClass({
     // id generated by the server. In a production application you would likely
     // not use Date.now() for this and would have a more robust system in place.
     comment.id = Date.now();
-    var newComments = comments.concat([comment]);
-    this.setState({data: newComments});
+    this.props.addComment(comment);
     $.ajax({
       url: this.props.url,
       dataType: 'json',
       type: 'POST',
       data: comment,
       success: function(data) {
-        this.setState({data: data});
+        this.props.showComments(data);
       }.bind(this),
       error: function(xhr, status, err) {
-        this.setState({data: comments});
+        this.props.showComments(comments);
         console.error(this.props.url, status, err.toString());
       }.bind(this)
     });

Congrats!

Redux Source

Redux は Data FlowAction, Reducer, Store に責務を分離するパラダイムです。
createStore の Source code を読むと、だいたいの流れがイメージできます。

Example

Redux は React がなくても単独で実行することができます。
JS Bin で動作するサンプルを作成しました。

HTML

  • cdnjs.cloudflare.comredux を参照します。
<!DOCTYPE html>
<html>
  <head>
    <title>JS Bin</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.5.2/redux.min.js"></script>
  </head>
  <body>
  </body>
</html>

JavaScrit

var createStore = Redux.createStore;
var store = createStore(function(state, action) {
  if (state === undefined) {
    return 0;
  }

  switch (action.type) {
  case 'PLUS':
    return state + action.number;
  case 'MINUS':
    return state - action.number;
  default:
    return state;
  }
});

store.subscribe(function () {
  return console.log(store.getState());
});

store.dispatch({type: 'PLUS', number: 2});
store.dispatch({type: 'PLUS', number: 3});
store.dispatch({type: 'MINUS', number: 4});
store.dispatch({type: 'DEFAULT'});

Console

  • 数値が増加するアクションや減少するアクションで State が更新されています。

redux_number

ECMAScript 2015

ECMAScript 2015 ならもっと簡潔に記述することができます。

import {createStore} from 'redux'
const store = createStore((state = 1, action) => action.type === 'PLUS' ? state + 1 : state - 1)
store.subscribe(() => console.log(store.getState()))
store.dispatch({type: 'PLUS'})

Data FlowAction, Reducer, Store に分離できました。
次は React tutorial で ECMAScript 2015 を使用しましょう!

22
22
1

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
22
22