Redux で mini Blog 機能


## はじめに
[Reduxのチュートリアル](http://redux.js.org/docs/basics/ExampleTodoList.html)をほんのちょっといじれば今自分が作りたいBlog機能を作成できるのでは？ということでそのプロトタイプを作成した。ほとんどTodoと変わらないが、編集機能の部分について工夫を入れている。

## サンプルコード

<a class="jsbin-embed" href="http://jsbin.com/vumupe/embed?js,output">JS Bin on jsbin.com</a><script src="http://static.jsbin.com/js/embed.min.js?3.39.11"></script>

## 機能の特徴

* 記事一覧と、記事作成を同一のスクリーンで行う
* 記事のタイトルと記事内容を書いて、ボタンをクリックすると記事一覧にそのボタンが作成した順に並ぶ（作成）
* 記事一覧の任意の記事をクリックすると、記事作成欄にその記事のタイトルと記事内容を表示する（編集）
* 記事一覧にある、各記事の[x]をクリックすると、その記事が消える（削除）
* 簡単のため、バリデーション処理は実装していない

## 気づき
### input要素に`props`のデータを渡す時の注意

* 記事一覧の任意の記事をクリックすると、記事作成欄にその記事のタイトルと記事内容を表示する（編集）

この機能を実現しようとすると、一連のフローは次のようになる。
[User Interaction(Click an Entry)] -> [Action(Modify)] -> [Store(CurrentEntry)] -> [Component]

この時、[Store(CurrentEntry)]を使って[Component]のinput要素の値を切り替えることになるが、そのやり方を発見するのにハマった。
`render()`の内部でこの情報を直接埋め込むことは、[controlled component](https://facebook.github.io/react/docs/forms.html#controlled-components)の制約でできない。

```js:これはできない
<input value={this.props.someVale} />
```

そこで内部ステータス[^1]を使って、ライフサイクル関数`componentWillReceiveProps(nextProps)`の中でその値`setState()`して目的を果たしている。

[^1]: [Reduxのチュートリアル](http://redux.js.org/docs/basics/ExampleTodoList.html) のような単にinput要素の値を使ってActionを発生させるだけなら要らない

```js
class AddEntry extends Component {
  
  constructor() {
    super();
    this.state = {
      title: '',
      content: ''
    };
  }

 
  componentDidMount() {
//  console.log('Add entry component Did mount');
  }
  
  componentWillReceiveProps(nextProp) {
//  console.log('componentWillReceiveProps')
    const { entry } = nextProp;
    this.setState({
      title: entry.title,
      content: entry.content
    })
  }
  
  render() {
    return (
      <div>
        <h2>Add Entry</h2>
        <form>
          <label>title</label><br />
          <input
            ref={node => this.titleInput = node}
            value={this.state.title || ''}
            onChange={e => {
              this.setState({title: e.target.value});
            }}
            type="text" /><br />
          <label>content</label><br />
          <textarea
            rows={10}
            cols={50}
            ref={node => this.contentInput = node}
            value={this.state.content || ''}
            onChange={e => {
              this.setState({content: e.target.value});
            }}
            /><br />
          <button
            onClick={(e)=>{
              e.preventDefault();
              store.dispatch(
                addEntry(
                  this.state.title,
                  this.state.content
                )
              );
              this.setState({
                content: '',
                title: ''
              });
            }}>
            add Entry
          </button>
        </form>
      </div>
    );    
  }
}
```

### connect()するとコンポーネントにstore情報は渡らない？
`connect()`すると`mapStateToProps()`で、ある時点のstoreの中身を編集し`props`の一部として渡す値を指定できる。ただ、そんなに手の込んだ編集がない場合は、わざわざ`mapStateToProps()`を定義しなくてもstoreの中身を取得するための代替案はないかな？と思ったが良い方法はなかった。

```js
// it doesn't work!!
const Entry = ({
// entries,
 handleClick,
 handleDeleteClick
},{
  { entries } 　// props から受け渡されなくても、 contextから取得できるとか・・
}
) => (
  <div>
    <div onClick={handleClick}>
      <span>{entry.title}</span>
      <br />
      <div
         dangerouslySetInnerHTML={{
         __html: entry.content.replace(/\n/g, '<br />') 
         }} />
      <span>{entry.createdAt ? entry.createdAt : 'no date'}</span>
    </div>
    <a onClick={handleDeleteClick}>[x]</a>
    <hr />
  </div>
       
);

/*
 * Conatainer Component (CurrentEntry)
 * 
const mapStateToEntryProps = (
  state,
  ownProps
) => {
  return {
    entry: ownProps.entry
  };
};
*/

const mapDispatchToEntryProps = (
  dispatch,
  ownProps
) => {
  return {
    handleClick() {
      dispatch({
        type: ActionType.SELECT_ENTRY,
        entry: ownProps.entry
      });
    },
    
    handleDeleteClick() {
      dispatch(deleteEntry(ownProps.entry.id));
    }
    
  };
};

const CurrentEntry = connect(
  null,
  mapDispatchToEntryProps
)(Entry);
```

## 終わりに
機能的な確認ができただけでなく、プレゼンテーショナルコンポーネントとコンテナコンポーネントをどのように切り分けていくと良いか、という方針をつかむための経験が積めた。
また、この記事には現れていないが、Reactを実装する前に、Reducerのテストが行える点、そしてReducerがコンパクトに分解できるのでテストしやすい点に好感を覚えた。