ReactでAjax – React入門

連載目次 : React入門
前回の記事 : Reactで作るTODOアプリ後編

今回は情報を前回作成したTODOアプリをAjaxで取得・更新が行えるように改造していきます。

あくまで練習なのでAPIにはJSON Serverを利用します。

環境構築

まずは「Create React App」を利用して環境を構築していきます。

以下のコマンドでReactのインストールを行います。

create-react-app todo-app-ajax
cd todo-app-ajax
npm install
npm start

これで http://localhost:3000 でReactアプリの表示が可能になります。

次にJSON Serverの設定を行います。
以下のコマンドでJSON Serverのインストールを行い、

npm install --save-dev json-server

db.json というファイル名で以下のようなJSONファイルを作成します。

{
  "todos": [
    {
      "id": 1,
      "title": "JavaScript覚える"
    },
    {
      "id": 2,
      "title": "jQuery覚える"
    }
  ]
}

標準では3000番ポートで立ち上がってしまうので、以下のコマンドで3001番ポートで立ち上がるように設定しています。

npx json-server --watch db.json --port 3001

App.jsは以下のように設定します。

  
import React, { Component } from 'react';
 
class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      todo: []
    };

    this.addTodo = this.addTodo.bind(this);
  }
  
  // 初期値の設定
  componentWillMount(){
    this.fetchResponse();
  }
  
  // リストの更新
  fetchResponse(){
    fetch('http://localhost:3001/todos')
    .then( res => res.json() )
    .then( res => {
      this.setState({
        todo : res
      });
    })
  }
  
  // 新規追加
  addTodo() {
    fetch('http://localhost:3001/todos', {
      method: 'POST',
      body: JSON.stringify({
        title: this.refs.newText.value
      }),
      headers: new Headers({ 'Content-type' : 'application/json' })
    }).then( () => {
      // リストの更新
      this.fetchResponse();
      // 値の初期化
      this.refs.newText.value = "";
    })
  }
  
  // 編集機能
  updateTodo(todo) {
    fetch(`http://localhost:3001/todos/${todo.id}`, {
      method: 'PUT',
      body: JSON.stringify({
        id: todo.id,
        title: todo.title
      }),
      headers: new Headers({ 'Content-type' : 'application/json' })
    })
  }
  
  // 削除機能
  deleteTodo(todo) {
    fetch(`http://localhost:3001/todos/${todo.id}`, {
      method: 'DELETE'
    }).then( () => {
      const todos = this.state.todo.filter(item => item.id !== todo.id)
      // 保存
      this.setState({
        todo : todos
      });
    })
  }
   
  render() {
    return (
      <div>
        <h1>TODOアプリ</h1>
        <ul>
        {this.state.todo.map( todo => (
          <li key={todo.id}>
            <input type="text" defaultValue={todo.title} onChange={e => todo.title = e.target.value} /> 
            <input type="button" value="編集" onClick={() => this.updateTodo(todo)}/>
            <input type="button" value="削除" onClick={() => this.deleteTodo(todo)}/>
          </li>
        ))}
        </ul>
        <input type="text" ref="newText" /> <input type="button" value="追加" onClick={this.addTodo} />
      </div>
   );
  }
}
  
export default App;  

各メソッドは以下のような内容になっています。

JSX部分

JSXでは現在のStateをli要素で表示して、値を入力フィールドに代入しています。
編集ボタンを押下時にupdateTodoメソッドを実行して、編集時にdeleteTodoメソッドを実行しています。
また、追加ボタン押下時にaddTodoメソッドを実行してTODOを追加しています。

  render() {
    return (</code></pre>
      <div>
        <h1>TODOアプリ</h1>
        <ul>
        {this.state.todo.map( todo => (
          <li key={todo.id}>
            <input type="text" defaultValue={todo.title} onChange={e => todo.title = e.target.value} /> 
            <input type="button" value="編集" onClick={() => this.updateTodo(todo)} />
            <input type="button" value="削除" onClick={() => this.deleteTodo(todo)} />
          </li>
        ))}
        </ul>
        <input type="text" ref="newText" />
        <input type="button" value="追加" onClick={this.addTodo}/>
      </div>
    );
  }

初期表示時

初期表示時にはライフサイクルイベントのcomponentWillMount()内でfetchResponseメソッドを実行しています。

  componentWillMount(){
    this.fetchResponse();
  }

Ajaxで情報を取得

fetchResponse()ではAjaxで取得したTODO一覧をStateにセットしています。

  fetchResponse(){
    fetch('http://localhost:3001/todos')
    .then( res => res.json() )
    .then( res => {
      this.setState({
        todo : res
      });
    })
  }

新規登録時

新規登録時にはAjaxで入力された値の更新を行ってからfetchResponse()で情報の再取得を行っています。

  addTodo() {
    fetch('http://localhost:3001/todos', {
      method: 'POST',
      body: JSON.stringify({
        title: this.refs.newText.value
      }),
      headers: new Headers({ 'Content-type' : 'application/json' })
    }).then( () => {
      // リストの更新
      this.fetchResponse();
      // 値の初期化
      this.refs.newText.value = "";
    })
  }

編集時

編集時には現在のTODO情報をPUTで送信しています。
Stateは入力のタイミングで変更されているため編集後にStateを操作する必要はないです。

  updateTodo(todo) {
    fetch(`http://localhost:3001/todos/${todo.id}`, {
      method: 'PUT',
      body: JSON.stringify({
        id: todo.id,
        title: todo.title
      }),
      headers: new Headers({ 'Content-type' : 'application/json' })
    })
  }

削除時

削除時には現在のTODO情報をDELETEで送信して削除を行います。
削除後には現在のStateから削除したTODOを取り除く必要があります。

  deleteTodo(todo) {
    fetch(`http://localhost:3001/todos/${todo.id}`, {
      method: 'DELETE'
    }).then( () => {
      const todos = this.state.todo.filter(item => item.id !== todo.id)
      // 保存
      this.setState({
        todo : todos
      });
    })
  }

これでReactでAjaxを利用することができるようなりました。

次回からはReactの新機能「React Hooks」について解説を行っていきます。

次回の記事 : React Hooks