【rails/非同期】いいね機能をReact.jsで実装してみた。その②

今日は、【rails/非同期】js初心者がいいね機能をReact.jsで実装してみた。その②

具体的なイベントの流れ

 - ~~①いいねボタンを押す~~
 - ~~②LikeモデルにajaxでPOSTする~~
 - ③いいねボタンのViewを更新する
 - ④いいね回数のViewを更新する

③のいいねボタンのViewを更新するから説明して行きたいと思います。

## 前回の内容はこちら
【rails/非同期】js初心者がいいね機能をReact.jsで実装してみた。その①
http://qiita.com/funao/items/60aa3d7e36cf93e0d832


## 前回は⑥ajaxでparams[:post_id]を送り、resuponseを受け取るコードを記述するところまでやりました

```js:like.js.jsx

Like = React.createClass({
    ajaxMain: function(method){
        $.ajax({
            url: this.props.url,                               //このURLは次でセットします
            type:method,                                       //今回はPOSTで送ります
            dataType: 'json',
            cache: false,
            data: {post_id: this.props.post},                  //このpostも次でセットします
            success: function(data) {
                if(data.like){                                 //ここはあとで活きてきます笑
                    this.setState({is_liked: data.liked});     //responseのlikedをstateのis_likedに反映させます
                };
                this.setState({counts: data.counts});          //responseのcountsをstateのcountsにに反映させます
            }.bind(this),                                      //bindしないとthisが使えなくてエラりますw
            error: function(xhr, status, err) {
                console.error(this.props.url, status, err.toString());
            }.bind(this)
        });
    },
    onClick: function(){
       this.ajaxMain("POST")
    },
    render: function(){
        return(
            <button onClick={this.onClick}>いいね!</button>
        );
    }
});

```

## ⑦次は、View側にいいね回数といいねボタンの状態を反映させます


```js:like.js.jsx

Like = React.createClass({
    ajaxMain: function(method){
        $.ajax({
            url: this.props.url,                               //このURLは次でセットします
            type:method,                                       //今回はPOSTで送ります
            dataType: 'json',
            cache: false,
            data: {post_id: this.props.post},                  //このpostも次でセットします
            success: function(data) {
                if(data.like){                                 //ここはあとで活きてきます笑
                    this.setState({is_liked: data.liked});     //responseのlikedをstateのis_likedに反映させます
                };
                this.setState({counts: data.counts});          //responseのcountsをstateのcountsにに反映させます
            }.bind(this),                                      //bindしないとthisが使えなくてエラりますw
            error: function(xhr, status, err) {
                console.error(this.props.url, status, err.toString());
            }.bind(this)
        });
    },
    onClick: function(){
       this.ajaxMain("POST")
    },
    render: function(){
        if(this.state.is_liked){
          return (
                <div>
                    <p>{this.state.counts}いいね</p>
                    <button onClick={this.onClick("DELETE")}>いいね 取り消し!</button>
                </div>
            );
        }else{
          return(
              <div>
                <p>{this.state.counts}いいね</p>
                <button onClick={this.onClick}>いいね!</button>
              </div>
          );
        }

    }
});

```

やったことは、まずいいねされているかどうかで条件分岐を行い、そののち、pタグ内にthis.state.countsに取得したいいね回数をぶち込んだだけです。

これで、stateを変更するだけで望んだViewが作成されるはずです。

## ⑧次にDELETE側の処理も書きましょう

さきほどの記述でonClick（"DELETE"）と書いたのでajaxでDELETEは送られるはずです。
なので、ControllerにDELETEの処理さえかけば完成です。

```rb:likes_controller.rb

# DELETE /likes/1
  # DELETE /likes/1.json
  def destroy
    @like = Like.find_by(user_id: current_user.id, post_id: params[:post_id])
    @like.destroy
    respond_to do |format|
      format.html { redirect_to :back, notice: 'Like was successfully destroyed.' }
      format.json { render json: {status: 'success', like: @like, counts: Like.where(post_id: params[:post_id]).count}, liked: false }
    end
  end

```

最後のlikedでしっかりとfalseを返してあげる事が大事です。

### ここまででほぼほぼ完成しました。

あとは、初期設定のみです。
新規にこのページを見たときに、自分がすでにいいねしているのかどうなのか取得する必要があります。

こんな時に使うのが`componentDidMount`という関数です。
この関数は、Componentが読み込まれた後に呼ばれる関数で、iosでいうとviewDidLoadと同じものと思われます。ほぼ。

なので、ここで現在のいいねの状況といいね数を取得してViewに反映させれば今回のいいね機能実装は完成です。

```js:like.js.jsx

Like = React.createClass({
    ajaxMain: function(method){
        $.ajax({
            url: this.props.url,                               //このURLは次でセットします
            type:method,                                       //今回はPOSTで送ります
            dataType: 'json',
            cache: false,
            data: {post_id: this.props.post},                  //このpostも次でセットします
            success: function(data) {
                if(data.like){                                 //ここはあとで活きてきます笑
                    this.setState({is_liked: data.liked});     //responseのlikedをstateのis_likedに反映させます
                };
                this.setState({counts: data.counts});          //responseのcountsをstateのcountsにに反映させます
            }.bind(this),                                      //bindしないとthisが使えなくてエラりますw
            error: function(xhr, status, err) {
                console.error(this.props.url, status, err.toString());
            }.bind(this)
        });
    },
    componentDidMount: function(){
        this.ajaxMain('GET');
    },
    render: function(){
        if(this.state.is_liked){
          return (
                <div>
                    <p>{this.state.counts}いいね</p>
                    <button onClick={this.ajaxMain.bind(this, this.state.is_liked ? 'DELETE' : 'POST')}>いいね 取り消し!</button>
                </div>
            );
        }else{
          return(
              <div>
                <p>{this.state.counts}いいね</p>
                <button onClick={this.ajaxMain.bind(this, this.state.is_liked ? 'DELETE' : 'POST')}>いいね!</button>
              </div>
          );
        }

    }
});

```

ajaxでGETが渡されるので対応するControllerを書きましょう。

```rb:likes_controller.rb

  def already_exists
    like = Like.find_by(user_id: current_user.id, post_id: params[:post_id]) 
    render json: { status: 'success', like: like, counts: Like.where(post_id: params[:post_id]).count, liked: like.present?}
  end

```

これで完成です！お疲れ様でしたー！
綺麗に動いていると思います。ダメだったらコメントください笑


それでは、大学の授業受けてきます笑