React Redux Rails 3 / 5 「新たなTodoを追加出来るようにする」
はじめに
Riot.js Redux Railsシリーズで作ったTodoアプリのRiot.js部分をReactを使って書いた。
Riot.js Redux Railsで作ったTodoアプリと全く同じものを作成するのでコードが大分重なっている(Riot.js部分をReactにしただけ)が、今回の一連の記事だけ読んでも出来るように省略はしない。
環境構築
- React Redux Rails 1 / 5 「環境構築」
Todo Appの作成
- React Redux Rails 2 / 5 「Todoリストを表示する」
- React Redux Rails 3 / 5 「新たなTodoを追加出来るようにする」
- React Redux Rails 4 / 5 「完了したTodoをチェック出来るようにする」
- React Redux Rails 5 / 5 「チェックしてあるタスクを削除出来るようにする」
最終的に完成したTodo App
https://github.com/atfeo/React_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/components/task-form.jsx import React from 'react'; export default class TaskForm extends React.Component { constructor(props) { super(props); this.handleSubmit = this.handleSubmit.bind(this); this.handleKeyup = this.handleKeyup.bind(this); } handleSubmit(e) { e.preventDefault(); this.props.addtask(this.newTask.value); this.newTask.value = ''; } handleKeyup(e) { this.props.handlekeyup(e.target.value); } render() { return ( <form onSubmit={this.handleSubmit}> <input type="text" ref={(ref) => this.newTask = ref} onKeyUp={this.handleKeyup} placeholder="new task" /> <button type="submit" disabled={!this.props.istext} > Add Task # {this.props.objects.length + 1} </button> </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.jsxのreducerに追加。
// ./client/src/index.jsx 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/components/todo-app.jsx import TaskForm from './task-form.jsx'; class TodoApp extends React.Component { constructor(props) { super(props); // 追加 this.handleNewTask = this.handleNewTask.bind(this); this.handleInputForm = this.handleInputForm.bind(this); } handleNewTask(task) { this.props.dispatch(actions.addTask(task)); } handleInputForm(value) { this.props.dispatch(actions.textExists(value)); } render() { return ( <div> <h3>Todo List</h3> <TaskForm addtask={this.handleNewTask} handlekeyup={this.handleInputForm} objects={this.props.tasks} istext={this.props.isText} /> {this.props.isLoading ... function mapStateToProps(state) { const { tasks, isLoading, isText } = state; return { tasks, isLoading, isText, }; }
cssを追加しUIをRiot公式のTodoに近づける。
/* ./app/assets/stylesheets/application.css */ body { font-family: 'myriad pro', sans-serif; font-size: 20px; border: 0; } div#content { 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をチェック出来るようにする。