関連記事
- Reactのスタート
- Reactのプロジェクト
- Reactで挨拶
- ReactでTrelloみたいなToDoリスト<1> props
- ReactでTrelloみたいなToDoリスト<2> state
- ReactでTrelloみたいなToDoリスト<3> prop-types
- ReactでTrelloみたいなToDoリスト<4> immutability-helper
作るもの
ToDoリストのイメージ
Appの構成
- KanbanBoardコンポーネントはTo Do、In Progress、Doneという三つのListコンポーネントを持つ。
- 各ListコンポーネントはCardコンポーネントを持つ。
- CardコンポーネントはCheckListコンポーネントを持つ。
ToDoリスト(immutable)
propsの伝達を理解するために、親コンポーネントから子コンポーネント順で作成する。
画面に表示するための仮データを持っているcardsListを作る。
KanbanBoardコンポーネントにcardsListをpropsとして渡す。
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に関するエラーで別途の記事で説明する予定だ。
他のエラーが表示されたらタイピングミスなので、修正しよう。
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;
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;
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;
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;
9ラインのspanタグは本のサンプルではlinkタグだった。
コンテンツを持っていなかったので、eslintエラーが出る。
なぜlinkタグがコンテンツを持ってなければならないのか?
それはSEOと関連がある。
アンカーテキストはSEO的に重要な意味を持つ。
これについては自ら検索してみよう。
ただeslintは本当に優れものだと分かっていただければと思う。
プログラマーに正しい道を教えてくれる道しるべみたいなものだ。
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;
}
ここまですると次の画面が表示される。
このサンプルではpropsを渡しているだけで、まだstateを扱っていない。
それで(immutable)なのだ。
次の記事でstateについて学ぶ。