2017/11/14
CodePenでReactを試してToDoリストを作ってみた
少し前にReactを体験するために、CodePenで簡単に始められるとのことでやってみました。
今はcreate-react-appというツールがあり環境構築は簡単になっていますが、当時は環境構築が大変と言われていました。
CodePenならcdnをいくつか読みこむだけでOKです。
なので今更ではありますが、やっと触ってみました。
Reactって?
facebook製のjavascriptライブラリです。(正式にはフレームワークではないらしいです)
UIに特化していることで、フレームワークではないみたいですね。
ただ、他のライブラリーを組み合わせればフレームワーク同等に使えるようです。
特徴としては、JSXを使用する点で、
ほぼhtmlは書かず、DOM部分もjavascriptで記述します。
javascriptといってもhtmlに近い形で記述することが出来るので少し注意すれば問題ないかと思います。
特徴の説明は下記ブログでわかり易く説明されているので、ご覧ください。
JSといえばjQueryだったWebデザイナーが、Reactを1年間使って感じたメリット | dwango creators' blog(ドワンゴクリエイターズブログ)
今回はタイトルにもあるように、reactでTodoリストを作ってみました。
See the Pen reactで簡単todoリスト by abe on CodePen.
CodePenの設定
JavaScript Preprocessorを「Babel」を設定し、
reactのcdnを読み込ませます。
この時は以下の2つを読み込んでいました。(※今はもう新しいverがでていますね…)
https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.js
https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.js
ToDoリスト作成
今回作ったTodoリストの内容としては、
・ToDoの追加・編集・削除
・ToDoの完了
・ToDoのソート
といったシンプルなもので、
データはlocalStorageを使用しました。
jsのコードをとりあえず載せます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | var todoListLS = []; //ローカルストレージ関係 var todoStorage = { get: function (todos) { todoListLS = JSON.parse(localStorage.getItem('simpleTodo') || '[]'); return todoListLS; }, save: function (todos) { todoListLS = todos; localStorage.setItem('simpleTodo', JSON.stringify(todoListLS)); } } class TodoAdd extends React.Component { constructor(props){ super(props); this.state = { newTodo: "" }; } handleChange(event){ this.setState({newTodo: event.target.value}); } handleNewTodoKeyDown(event){ if (event.keyCode !== 13) { return; } var val = this.state.newTodo; this.props.onTodoSubmit({title: val,check:false}) if (val) { this.setState({newTodo: ''}); } } render() { return ( <input type="text" placeholder="タスクを記入" className="add" onKeyDown={this.handleNewTodoKeyDown.bind(this)} onChange={this.handleChange.bind(this)} value={this.state.newTodo} /> ) } } class TodoItem extends React.Component { handleDelete(){ this.props.onTodoDelete(this.props.todo.id); } handleEdit(event){ var title = event.target.value; this.props.onTodoEdit(this.props.todo.id,title); } toggleCheck(event) { var checked = event.target.checked; this.props.onTodoCheck(this.props.todo.id,checked); } render() { return( <li> <label><input type="checkbox" name="check" checked={this.props.todo.check} onChange={this.toggleCheck.bind(this)} /><span className="icon-checkmark-circle"></span></label> <input type="text" name="task" value={this.props.todo.title} onChange={this.handleEdit.bind(this)} /> <span className="delete icon-trash" onClick={this.handleDelete.bind(this)}></span> </li> ); } } class Todo extends React.Component { constructor(props){ super(props); this.state = { todos: todoStorage.get(), sortfilter: "all" }; } handleTodoAdd(todo) { todo.id = new Date(); const newTodo = this.state.todos.concat(todo); this.setState({todos: newTodo}); } handleTodoEdit(id,title) { const newTodo = this.state.todos.map((todo) => { if(todo.id == id){ todo.title = title; } return todo; }) this.setState({todos: newTodo}); } handleTodoDelete(id) { const newTodo = this.state.todos.filter((todo) => { return todo.id !== id; }) this.setState({todos: newTodo}); } handleTodoCheck(id,check) { const newTodo = this.state.todos.map((todo) => { if(todo.id == id){ todo.check = check; } return todo; }) this.setState({todos: newTodo}); } handleTodoSort(event) { this.setState({sortfilter: event.target.value}); } componentWillUpdate(nextProps,nextState){ todoStorage.save(nextState.todos); } render() { const filterTodos = this.state.todos.filter((todo) => { var filterTask = this.state.sortfilter; if(filterTask == "all"){ return todo; }else if(filterTask == "complete"){ return todo.check; }else if(filterTask == "incomplete"){ return !todo.check; } }) const todoItems = filterTodos.map((todo) => { return ( <TodoItem key={todo.id} todo={todo} onTodoEdit={this.handleTodoEdit.bind(this)} onTodoDelete={this.handleTodoDelete.bind(this)} onTodoCheck={this.handleTodoCheck.bind(this)} /> ) }) return( <div className="contents"> <h1>Todo</h1> <div className="main todoList"> <TodoAdd onTodoSubmit={this.handleTodoAdd.bind(this)} /> <ul className="lists"> {todoItems} </ul> <div className="filters"> <select name="todoChange" onChange={this.handleTodoSort.bind(this)} > <option value="all">All Tasks</option> <option value="incomplete">Incompelete Tasks</option> <option value="complete">Complete Tasks</option> </select> </div> </div> </div> ); } } ReactDOM.render( <Todo />, document.getElementsByClassName('wrapper')[0] ); |
細かい解説は省かせてもらいますが、
・ToDo
・TodoItem
・TodoAdd
という3つのコンポーネントを作って構成してます。
コンポーネントを親子関係にした時に、子と親のデータのやりとりが最初戸惑うので、
理解するまでは参考のコードを見てその通りにするのがいいと思います。
長く複雑に見えるかもしれませんが、お作法的な文が長いだけでやっている事自体はそこまで難しいわけではないので、
これも慣れてくれば心地よいのかもしれません。
ルールがしっかりと決まっているので、自分で作ってしばらくした後に見ても(実際このコードを半年ぶりに見ました…)
他人が見てもある程度流れがわかるので、コードの質としてはそれなりに担保されたものが出来るかと思います。
複数人数でやるのにいいですね!
残念ながら実務の案件でReactをやることがないので、なかなか触ることはありません。。。
今度はAngularに挑戦してみたいと思います。
Author Profile
スターフィールド編集部
SHARE