ReactでTrelloみたいなToDoリスト＜1＞ props


## 関連記事

* [Reactのスタート](http://qiita.com/park-jh/items/63bf0f013c998c5572aa)
* [Reactのプロジェクト](http://qiita.com/park-jh/items/488d43e2d0b87991207e)
* [Reactで挨拶](http://qiita.com/park-jh/items/bffaec5d05a96850e91b)
* ReactでTrelloみたいなToDoリスト＜1＞ props
* [ReactでTrelloみたいなToDoリスト＜2＞ state](http://qiita.com/park-jh/items/0b71fd9c7e6cc8cbe844)
* [ReactでTrelloみたいなToDoリスト＜3＞ prop-types](http://qiita.com/park-jh/items/6a8eac233e3f3ae61f32)
* [ReactでTrelloみたいなToDoリスト＜4＞ immutability-helper](http://qiita.com/park-jh/items/6166434f80bc186f8c77)


## 作るもの

### ToDoリストのイメージ

![스크린샷 2017-06-20 10.46.31.png](https://qiita-image-store.s3.amazonaws.com/0/93752/11bde098-9b06-c3ca-2003-f4f5aa8e0c60.png "스크린샷 2017-06-20 10.46.31.png")

### Appの構成

![스크린샷 2017-06-20 10.47.31.png](https://qiita-image-store.s3.amazonaws.com/0/93752/038ffb85-82b9-461e-255d-3e562acbea4e.png "스크린샷 2017-06-20 10.47.31.png")

* KanbanBoardコンポーネントはTo Do、In Progress、Doneという三つのListコンポーネントを持つ。
* 各ListコンポーネントはCardコンポーネントを持つ。
* CardコンポーネントはCheckListコンポーネントを持つ。

## ToDoリスト（immutable）

propsの伝達を理解するために、親コンポーネントから子コンポーネント順で作成する。
画面に表示するための仮データを持っているcardsListを作る。
KanbanBoardコンポーネントにcardsListをpropsとして渡す。

```javascript:src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import KanbanBoard from './components/KanbanBoard';
import registerServiceWorker from './registerServiceWorker';
import './index.css';

const cardsList = [
  {
    id: 1,
    title: 'Read the Book',
    description: 'I should read the whole book',
    status: 'in-progress',
    tasks: [],
  },
  {
    id: 1,
    title: 'Write some code',
    description: 'Code along with the samples in the book',
    status: 'todo',
    tasks: [
      {
        id: 1,
        name: 'ContactList Example',
        done: true,
      },
      {
        id: 2,
        name: 'Kanban Example',
        done: false,
      },
      {
        id: 3,
        name: 'My own experiments',
        done: false,
      },
    ],
  },
];

ReactDOM.render(<KanbanBoard cards={cardsList} />, document.getElementById('root'));
registerServiceWorker();
```

eslintからのエラーが表示されるが気にしないで欲しい。
これらはpropsに関するエラーで別途の記事で説明する予定だ。
他のエラーが表示されたらタイピングミスなので、修正しよう。

```javascript:src/components/KanbanBoard.js
    1 import React, { Component } from 'react';
    2 import List from './List';
    3
    4 class KanbanBoard extends Component {
    5   render() {
    6     return (
    7       <div className="app">
    8         <List
    9           id="todo"
   10           title="To Do"
   11           cards={
✗  12             this.props.cards.filter((card) => card.status === 'todo')
   13           }
   14         />
   15         <List
   16           id="in-progress"
   17           title="In Progress"
   18           cards={
✗  19             this.props.cards.filter((card) => card.status === 'in-progress')
   20           }
   21         />
   22         <List
   23           id="done"
   24           title="Done"
   25           cards={
✗  26             this.props.cards.filter((card) => card.status === 'done')
   27           }
   28         />
   29       </div>
   30     );
   31   }
   32 }
   33
   34 export default KanbanBoard;
```

```javascript:src/components/List.js
    1 import React, { Component } from 'react';
    2 import Card from './Card';
    3
    4 class List extends Component {
    5   render() {
✗   6     const cards = this.props.cards.map((card) => {
    7       return (<Card
    8         id={card.id}
    9         title={card.title}
   10         description={card.description}
   11         tasks={card.tasks}
   12       />
   13       );
   14     });
   15
   16     return (
   17       <div className="list">
✗  18         <h1>{this.props.title}</h1>
   19         {cards}
   20       </div>
   21     );
   22   }
   23 }
   24
   25 export default List;
```

```javascript:src/components/Card.js
    1 import React, { Component } from 'react';
    2 import CheckList from './CheckList';
    3
    4 class Card extends Component {
    5   render() {
    6     return (
    7       <div className="card">
✗   8         <div className="card__title">{this.props.title}</div>
    9         <div className="card__details">
✗  10           {this.props.description}
✗  11           <CheckList cardId={this.props.id} tasks={this.props.tasks} />
   12         </div>
   13       </div>
   14     );
   15   }
   16 }
   17
   18 export default Card;
```

```javascript:src/components/CheckList.js
    1 import React, { Component } from 'react';
    2
    3 class CheckList extends Component {
    4   render() {
✗   5     const tasks = this.props.tasks.map((task) => (
    6       <li className="checklist__task">
    7         <input type="checkbox" defaultChecked={task.done} />
    8         {task.name}
✗   9         <span className="checklist__task--remove" />
   10       </li>
   11     ));
   12
   13     return (
   14       <div className="checklist">
   15         <ul>{tasks}</ul>
   16       </div>
   17     );
   18   }
   19 }
   20
   21 export default CheckList;
```

\:bulb: [anchor-has-content](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/anchor-has-content.md)について
<details>
9ラインのspanタグは本のサンプルではlinkタグだった。
コンテンツを持っていなかったので、eslintエラーが出る。
なぜlinkタグがコンテンツを持ってなければならないのか？
それはSEOと関連がある。
アンカーテキストはSEO的に重要な意味を持つ。
これについては自ら検索してみよう。
ただeslintは本当に優れものだと分かっていただければと思う。
プログラマーに正しい道を教えてくれる道しるべみたいなものだ。
</details>

cssファイルはタイピングせずにコピペしよう。

```css:src/index.css
*{
  box-sizing: border-box;
}

html,body,#root {
  height:100%;
  margin: 0;
  padding: 0;
}

body {
  background: #eee;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}

h1{
  font-weight: 200;
  color: #3b414c;
  font-size: 20px;
}

ul {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

.app {
  white-space: nowrap;
  height:100%;
}

.list {
  position: relative;
  display: inline-block;
  vertical-align: top;
  white-space: normal;
  height: 100%;
  width: 33%;
  padding: 0 20px;
  overflow: auto;
}

.list:not(:last-child):after{
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: 1px;
  height: 99%;
  background: linear-gradient(to bottom, #eee 0%, #ccc 50%, #eee 100%) fixed;
}

.card {
  position: relative;
  z-index: 1;
  background: #fff;
  width: 100%;
  padding: 10px 10px 10px 15px;
  margin: 0 0 10px 0;
  overflow: auto;
  border: 1px solid #e5e5df;
  border-radius: 3px;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
}

.card__title {
  font-weight: bold;
  border-bottom: solid 5px transparent;
}

.card__title:before {
  display: inline-block;
  width: 1em;
  content: '▸';
}

.card__title--is-open:before {
  content: '▾';
}

.checklist__task:first-child {
  margin-top: 10px;
  padding-top: 10px;
  border-top: dashed 1px #ddd;
}

.checklist__task--remove:after{
  display: inline-block;
  color: #d66;
  content: "✖";
}

.checklist--add-task {
  border: 1px dashed #bbb;
  width: 100%;
  padding: 10px;
  margin-top: 5px;
  border-radius: 3px;
}
```

ここまですると次の画面が表示される。

![스크린샷 2017-06-22 19.08.20.png](https://qiita-image-store.s3.amazonaws.com/0/93752/b18e52f5-5b3e-a31a-8b65-12eea6bc9e9f.png "스크린샷 2017-06-22 19.08.20.png")

このサンプルではpropsを渡しているだけで、まだstateを扱っていない。
それで（immutable）なのだ。
次の記事でstateについて学ぶ。