Rails+ReactでAjaxいいねボタンを作る方法

#はじめに
Ruby on Rails と React を用いてSPAのポートフォリオを作る中でAjaxでいいねボタンを作る必要があったのでその方法をシェアしたいと思います. 細かいcontrollerやmodelの作成については書いておりませんのでご了承ください. 
なお, いいねボタンのアイコンにはFont Awesomeを使用します. 

```
【動作環境】
Rails 6.1.4
react-rails の gemを使用
```

#1. Font Awesome からハートマークをインストール

```sh
$ yarn add @fortawesome/free-solid-svg-icons
$ yarn add @fortawesome/free-regular-svg-icons
```
↓公式ページの通りインストール

https://fontawesome.com/v5.15/how-to-use/on-the-web/using-with/react



#2. フロント側の実装

```react
import React, { useState } from 'react'
import { faHeart as LikeImage} from '@fortawesome/free-solid-svg-icons'
import { faHeart as UnikeImage } from "@fortawesome/free-regular-svg-icons"


function LikeButton(props) {
  const [isLiked, setIsLiked] = useState(props.is_liked)
  const [likedNumber, setLikedNumber] = useState(props.liked_number)

  const clickLikeButton = () =>{
     const getCsrfToken = () => {
       const metas = document.getElementsByTagName('meta');
       for (let meta of metas) {
           if (meta.getAttribute('name') === 'csrf-token') {
               return meta.getAttribute('content');
            }
        }
       return '';
     }

     //以下には適宜ポストするデータを入れる
     const data = { like: {user_id: props.user_id, report_id: props.report_id} }
     
     //いいねする, いいねを外すのどちらも処理するため, isLikedに合わせてルーティングを変える
     let method_type = ''
     let fetch_route = ''
     if(isLiked){
       fetch_route = '/likes/' + props.report_id
       method_type = 'DELETE'
     }else{
       fetch_route = '/likes'
       method_type = 'POST'
     }
     setIsLiked(!isLiked)
     etch(fetch_route,{
      method: method_type,
      headers: {
                'Content-Type': 'application/json',
                'X-CSRF-Token': getCsrfToken()
      },
        body: JSON.stringify(data)
      })
      .then(res => res.json())
      .then((result) => {
        if(result[0] == "Successful registration of like" || result[0] == "Success to destroy like")
           //成功したときの処理を書く
           setLikedNumber(result[1])
        }else if(result[0] == "Failed to register like" || result[0] == "Failed to destroy like"){
           //失敗したときの処理を書く
        }else{
           //ログインしていない時の処理を書く
           alert("ログインしていないとその操作はできません")
        }
      }
    }
  }

  let like_button;
  if (isLiked){
    like_button = <div>
                       <button onClick={()=>{clickLikeButton()}}>
                          <FontAwesomeIcon icon={LikeImage} style={{"color": "red"}}/>
                       </button>
                   </div>
  }else{
    like_button = <div>
                       <button onClick={()=>{clickLikeButton()}}>
                          <FontAwesomeIcon  icon={UnikeImage} style={{"color": "red"}}/>
                       </button>
                   </div>
  }

  return (
    <div>
      {like_button}
      {likedNumber}
    </div>
  );
}
```

#3. バックエンド側の実装

```ruby:likes_contorller.rb
class LikesController < ApplicationController
  def create
    if logged_in?
      @like = Like.new(secure_like_infomation)
      if @like.save
        likes_number = Like.where(report_id: params[:like][:report_id]).count
        render :json => ["Successful registration of like", likes_number]
      else
        render :json => ["Failed to register like", @like.errors.full_messages]
      end
    else
      render :json => ["this operation cannot be performed without logging in"]
    end
  end

  def destroy
    if logged_in?
      @like = Like.find_by(secure_like_infomation)
      if @like.destroy
        likes_number = Like.where(report_id: params[:like][:report_id]).count
        render :json => ["Success to destroy like", likes_number]
      else
        render :json => ["Failed to destroy like"]
      end
    else
      render :json => ["this operation cannot be performed without logging in"]
    end
  end

  private
    def secure_like_infomation
      params.require(:like).permit(:user_id,:report_id)
    end

end

```

#終わりに
気になるところなどあればコメントいただければと思います。