Riot.js Redux Rails 6 / 8 「新たなTodoを追加出来るようにする」
はじめに
フロントにRiot.jsとReduxを使いサーバーサイドにRailsを使い、初めに環境構築し、次にReduxの使い方の流れをみて、最終的に簡単なTodoAppを作成する。
環境構築
- Riot.js Redux Rails 1 / 8 「環境構築」
簡単な例でReduxの流れをみる
- Riot.js Redux Rails 2 / 8 「Reduxを使ってtitleを表示させる」
- Riot.js Redux Rails 3 / 8 「formを追加しtitleの変更を可能にする」
- Riot.js Redux Rails 4 / 8 「3で作成したformを、title-formタグとして独立させる」
Todo Appの作成
- Riot.js Redux Rails 5 / 8 「Todoリストを表示する」
- Riot.js Redux Rails 6 / 8 「新たなTodoを追加出来るようにする」
- Riot.js Redux Rails 7 / 8 「完了したTodoをチェック出来るようにする」
- Riot.js Redux Rails 8 / 8 「チェックしてあるタスクを削除出来るようにする」
最終的に完成したTodo App
https://github.com/atfeo/Riot_Redux_Rails
参考
Rails
新たなTodoを追加する際のサーバー側の処理を作成する。
Controller
tasks_controller.rbに
# ./app/controllers/api/tasks_controller.rb def create @task = Task.new(task_params) if @task.save render :show, status: :created else head :unprocessable_entity end end private def task_params params.permit(:name) end
を追加。
View(JSON)
保存に成功したときにJSON返すshow.json.jbuilderを作成。
# ./app/views/api/tasks/show.json.jbuilder json.extract! @task, :id, :name
これでサーバー側は完成。
Todoを追加するためのtask-formタグ
UIをRiot公式のTodoのように作成する。 + フォームに入力があった時にボタンが有効になるようにする。 + 何個目のTodoを登録しようとしているかわかるようにする。
// ./client/src/tags/task-form.tag <task-form> <form onsubmit={handleSubmit}> <input type="text" name="newTask" onkeyup={handleKeyup} placeholder="new task" > <button type="submit" disabled={!this.opts.istext} > Add Task # {this.opts.objects.length + 1} </button> </form> <script> handleSubmit() { if (!this.newTask.value) { return } this.opts.addtask(this.newTask.value) this.newTask.value = '' } handleKeyup() { this.opts.handlekeyup(this.newTask.value) } </script> </task-form>
サーバーに新しいタスクを送るメソッドなどをactions.jsに追加。
// ./client/src/actions.js module.exports = { loadTasks, // 追加 addTask, textExists, }; // 追加 function addTask(newTask) { return (dispatch) => { dispatch(toggleLoading(true)); $.ajax({ url: '/api/tasks.json', type: 'POST', dataType: 'json', data: { name: newTask }, success: (res) => { dispatch(newTaskAdded(res.id, res.name)); dispatch(toggleLoading(false)); }, error: (xhr, status, err) => { dispatch(toggleLoading(false)); console.log('/api/tasks.json', status, err.toString()); }, }); }; } function newTaskAdded(id, name) { return { type: 'TASK_ADDED', data: { id, name } }; } function textExists(value) { return { type: 'TEXT_EXISTS', data: value }; }
タグをマウントするための処理と、アクションを送られたときの処理をindex.jsに追加。
// ./client/src/index.js import './tags/task-form.tag'; // reducerに追加 case 'TASK_ADDED': return Object.assign({}, state, { tasks: state.tasks.concat(action.data) }); case 'TEXT_EXISTS': return Object.assign({}, state, { isText: action.data });
todo-appタグにtask-formタグ、h3タグ、メソッドを追加
<!-- ./client/src/tags/todo-app.tag --> <todo-app> <h3>Todo List</h3> <task-form addtask={this.handleNewTask} handlekeyup={handleInputForm} objects={this.state.tasks} istext={this.state.isText}> </task-form> <loading- ...> // scriptに追加 handleNewTask(task) { store.dispatch(actions.addTask(task)) } handleInputForm(value) { store.dispatch(actions.textExists(value)) }
CSSの追加
cssを追加しUIをRiot公式のTodoに近づける。
/* ./app/assets/stylesheets/application.css */ body { font-family: 'myriad pro', sans-serif; font-size: 20px; border: 0; } todo-app { display: block; max-width: 600px; margin: 5% auto; } form input { font-size: 85%; padding: .4em; border: 1px solid #ccc; border-radius: 2px; } button { background-color: #1FADC5; border: 1px solid rgba(0,0,0,.2); font-size: 75%; color: #fff; padding: .4em 1.2em; border-radius: 2em; cursor: pointer; margin: 0 .23em; outline: none; } button[disabled] { background-color: #ddd; color: #aaa; } ul { padding: 0; } li { list-style-type: none; padding: .2em 0; }
ブラウザでlocalhost:5000を更新して確認。
フォームにタスクの名前を入力しボタンを押して登録できること、更新後も登録したTodoが維持されていることを確認。
次回は完了したTodoをチェック出来るようにする。