reduxを試してみた(2日目) - React.jsを学ぶ

  • 65
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

React.jsと組み合わせるfluxのライブラリreduxを試してみた。 このページは作業ログです。やったことをつらつら書くだけなのでまとめません。あしからず。

対象読者

  • 主に自分

今日のゴール

  • Reactの構成を理解できていること
  • Reactコンポーネントのイベントハンドラの設定が理解できていること

やったことメモ

Reactのドキュメントを読む

チュートリアル(日本語)。に目を通しつつ、手を動かす。

チュートリアルの結果

感想

  • 手を動かしながら学べるのは良い
  • <script type="text/jsx">の中に実装をしていく?まず、tutorial1.jsを実装してみる。
  • コンポーネントの定義ができる下記のようなスニペットがあるとよさそう
       var Component = React.createClass({
         render : function(){
           return (
             // write JSX
           );
         }
       });
  • ES6だと下記のように記述できる
import {Component} from 'react';

class Hoge extends Component {
  render() {
    return (
      // write JSX
    );
  }
}
  • Componentに対するイベントハンドラは下記のように定義したクラスの中のfunctionで定義できる。onSubmit={this.handleSubmit}の辺りが該当コード。
       var CommentForm = React.createClass({
         handleSubmit : function(e) {
           // ...
         },
         render : function() {
           return (
           <form className="commentForm" onSubmit={this.handleSubmit}>
             <input type="text" placeholder="Your Name..." ref="author"/>
             <input type="text" placeholder="Say somethings..." ref="text"/>
             <input type="submit" value="Post"/>
           </form>
           );
         }
       });
  • this.propsってもしかして親コンポーネントなのか?→違う自Componentのプロパティ。<CommentForm onCommentSubmit={this.handleCommentSubmit}/>の例だと、呼び出し元でイベントハンドラonCommentSubmitが追加されている。
      var CommentForm = React.createClass({
        handleSubmit : function(e) {
          e.preventDefault();
          var author = React.findDOMNode(this.refs.author).value.trim();
          var text = React.findDOMNode(this.refs.text).value.trim();
          if (!author || !text) {
            console.log('invalid value');
            return;
          }
          // TODO: submit data to server
          this.props.onCommentSubmit({author: author, text: text}); // onCommentSubmitはCommentFormに追加したイベントハンドラ
          React.findDOMNode(this.refs.author).value = '';
          React.findDOMNode(this.refs.text).value = '';
          return;
        },

チュートリアル以外

Reusable Component

ドキュメント

Classの定義
  • ES6環境ではコンポーネントは下記のように継承を使って定義可能
class HelloMessage extends React.Component {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}
propTypes
  • コンポーネントにプロパティを設定した時にバリデーションする
  • 開発時のみ有効になるらしい→プロダクション環境への切り替えはどうやるの?
  • 型チェックやら必須チェックやら
  • 新規に関数を作成したらカスタムバリデータとして機能

Reduxのチュートリアルに戻る

2.5 Reactとつなげる

ドキュメント

AddTodoTodoListTodoFooterどれもDumb Component。データがどこから来てどう変更するのか知らなくてもOKなので、Reduxに依存しなくても大丈夫。

ReactのコンポーネントとReduxを接続するには

  1. react-reduxを依存に追加
  2. 下記のindex.jsのようにSmart Componentであるコンテナを<Provider>でラップする(Providerはreact-redux/Provider)
  3. Appコンポーネントの定義App.jsで、react-redux/connect()を使って接続する
index.js
let rootElement = document.getElementById('root');
React.render(
  // The child must be wrapped in a function
  // to work around an issue in React 0.13.
  <Provider store={store}>
    {() => <App />}
  </Provider>,
  rootElement
);
App.js
// Wrap the component to inject dispatch and state into it
export default connect(select)(App);

上記のconnectでApp.propsstore.dispatchが追加になり、App.statestore.getState()がバインドされる。つまり、reduxのstoreの変更がApp.stateの変更になる?

react-reduxのリポジトリを見る
container/CounterContainer.js
import { Component } from 'react';
import { connect } from 'react-redux';

import Counter from '../components/Counter';
import { increment } from '../actionsCreators';

// Which part of the Redux global state does our component want to receive as props?
function mapStateToProps(state) {
  return {
    value: state.counter
  };
}

// Which action creators does it want to receive by props?
function mapDispatchToProps(dispatch) {
  return {
    onIncrement: () => dispatch(increment())
  };
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Counter);

react-redux/connect()の引数にReduxのグローバルな状態とコンポーネントのプロパティをマップする関数と、コンポーネントのプロパティをReduxのActionにマップする関数がある。Counter.valuestate.counterを、Counter.onIncrementdispatch(increment()をバインドしてる、ということか。ということは、App.jsselectも大事。

App.js
// Which props do we want to inject, given the global state?
// Note: use https://github.com/faassen/reselect for better performance.
function select(state) {
  return {
    visibleTodos: selectTodos(state.todos, state.visibilityFilter),
    visibilityFilter: state.visibilityFilter
  };
}

App.visibleTodosselectTodos()の結果を、App.visibilityFilterstate.visibilityFilterを割り当てる。

redux#bindActionCreators()はActionを返すメソッド群をそれぞれdispatch()でラップし、さらに1つのオブジェクトにまとめあげるユーティリティ。

2日目で学んだこと

  • Reactのチュートリアルはわかりやすい
  • reduxのstoreとReactのコンポーネントのバインディング方法もわかった
  • ボイラープレートベースでいいから簡単なアプリを作成したい

関連エントリ