Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

【2016/12/17 追記】
React(flux)を使ったブログエンジンを開発しました!
何か参考になれば嬉しいです!

Notee
https://github.com/funaota/notee


最近なにかと流行のreact先生に今回思い切ってチャレンジしてみる事にしました。(遅め笑)

react触った印象

  • VirtualDOMにはめっちゃ感動しました。
  • id指定して、innerTextをどうたらこうたらってやらなくていいこと
  • State変更するだけでViewも変更されるんは熱い!
  • 思ってたよりも簡単!

ちょっとなと思ったところ

  • jsxの書き方嫌いな人は嫌いそう笑
  • jsx内で条件分岐のcodeとか書きにくい(component化したほうがいいとかなんとか、まだよくわからん)
  • jsx内でインスタンス変数とかアクセス出来ない(?)

今回やったこと

今回やったことは、タイトル通り、『いいね機能の実装』です。
Facebookのいいね機能をイメージしてもらえれば大丈夫だと思います。

具体的なLikeモデルのSchemaは以下になっています。

Like
# == Schema Information
#
# Table name: likes
#
#  id         :integer          not null, primary key
#  user_id    :integer          not null
#  post_id    :integer          not null
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

具体的なイベントの流れは

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

上記の流れでDELETE versionも実装しました。

さて早速実装内容について説明します。

①reactを使える環境にする

詳しくはここを見てください
https://github.com/reactjs/react-rails#reactjs-builds

Gemfile
gem 'react-rails', '~> 1.7.0'

$ bundle install
$ rails g react:install

config/environments/development.rb
Rails.application.configure do

  ...

  config.react.variant = :development

  ...

end

②Componentをgenerateします

rails g react:component Like

このコマンドをうつと、app/assets/javascripts/componentslike.js.jsxが生成されます。
このファイルに実際のコードを書いて行きます。

③とりあえず、Hello World!を表示させるためのjsを完成させ、react_componentで表示させる

Hello World!を表示させるためのjsはこんな感じ

like.js.jsx
Like = React.createClass({
  render: function() {
    return(
      <div>Hello World!</div>
    );
  }
});

View側はこう書く

posts.html.slim
- @posts.each do |post|
  p = post.title
  = react_component 'Like'

これで、HelloWorldが、各Postに表示されるはずです。
ここのHelloWorldをいいねボタンに変えて、処理をすれば完成です!
じゃあ、いよいよ本題に入ります。

④いいねButtonのView作成と、対応するメソッドを用意します。

Viewの作成

<button onClick={this.ajaxMain}>いいね!</button>
Buttonタグで作成し、onClickでjs内のメソッドを指定する

対応するメソッドの作成

ajaxMain: function(){
  console.log("hello world!");
}

とりあえず、hello worldとコンソールに表示させるコードにします。
以下が全体のコードになります。

like.js.jsx
Like = React.createClass({

  ajaxMain: function(){
    console.log("hello world!");
  }

  render: function(){
    return(
      <button onClick={this.ajaxMain}>いいね!</button>
    );
  }
});

これで、いいねボタンのViewが表示され、ボタンを押すと、
consoleに"hello world"に表示されるはずです。

⑤使用するStateを定義する

今回は以下のStateを持つ事にします。

  • いいねの合計数
  • いいねされているかどうかの状態
like.js.jsx
Like = React.createClass({

  getInitialState: function(){
      return {
          counts: 0,         //いいねの合計数
          is_liked: false    //いいねされているかどうかの状態
      };
  },

  ajaxMain: function(){
      console.log("hello world!");
  }

  render: function(){
      return(
        <button onClick={this.ajaxMain}>いいね!</button>
      );
  }
});

⑤LikeをCreateするメソッドを用意します。

Controllerの流れ

  • ①ajaxでparams[:post_id]を受け取る
  • ②Likeを作成する
  • ③jsonで、status(ajaxが成功したかどうか)、like(あとで使う笑)、counts(いいねの合計数)、liked(いいねされてるかどうか)を返す
likes_controller.rb
  def create
    @like = Like.new(user_id: current_user.id, post_id: params[:post_id])

    respond_to do |format|
      if @like.save
        format.html { redirect_to :back, notice: 'Like was successfully created.' }
        format.json { render json: {status: 'success', like: @like, counts: Like.where(post_id: @like.post_id).count, liked: true} }
      else
        format.html { render :new }
        format.json { render json: @like.errors, status: :unprocessable_entity }
      end
    end
  end

⑥ajaxでparams[:post_id]を送り、resuponseを受け取るコードを記述する

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)
        });
    },

    render: function(){
        return(
            <button onClick={this.ajaxMain.bind(this, "POST")}>いいね!</button>
        );
    }
});

⑦view側で、propsにパラメーターを渡します。

api_likes_urlは、routeで指定したajaxのapiを指定します。環境に会わせて随時変更してください。

posts.html.slim
- @posts.each do |post|
  p = post.title
  = react_component 'Like', post: post.id, url: api_likes_url

これで、ひとまずLikeを非同期で作成するまで完成しました!

具体的なイベントの流れ

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

次は③から活きたいと思います。

今日もまた蛍の光がお店でなりだしたので、続きはまた明日!!
Reactの説明難しい…

その②もかきますた!

http://qiita.com/funao/items/979be14210abbbc9b493#_reference-0bfc15f8e74dae27325c

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away