Learn プログ

-マナビメモ-

Riot.js Redux Rails 6 / 8 「新たなTodoを追加出来るようにする」

はじめに

フロントにRiot.jsとReduxを使いサーバーサイドにRailsを使い、初めに環境構築し、次にReduxの使い方の流れをみて、最終的に簡単なTodoAppを作成する。

環境構築

簡単な例でReduxの流れをみる

Todo Appの作成

最終的に完成した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をチェック出来るようにする。

Riot.js Redux Rails 7 / 8に続く