Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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のコンポーネントのバインディング方法もわかった
  • ボイラープレートベースでいいから簡単なアプリを作成したい

関連エントリ

freee
スモールビジネスのバックオフィス業務をテクノロジーで自動化し、日本のスモールビジネスを元気にする
http://www.freee.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした