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

Tornado(websocket)とVueを使ってTwitterのトレンドを表示する

出来上がったもの

こちら
ソースコード

Tornadoについて

公式ドキュメント
Facebookにより開発されているPythonで書かれたWebフレームワーク。
ノンブロッキングI/Oを使用しているので、WebSocketなど長期接続を必要とするアプリケーションに最適だとドキュメントで紹介されています。

アプリケーションの概要

TwitterApiでトレンドを一定間隔で取得websocketでクライアントにプッシュVue.jsでリストレンダリング

という単純なものです。

サーバーサイド

公式のwebsocketデモアプリを少し改変した程度です。

トレンドを一定間隔で取得する

app.py
api = tweepy.API(auth)
regional_id = {}
for place in api.trends_available():
    if place['countryCode'] == 'JP':
        regional_id[place['name']] = place['woeid']
JP = regional_id['Japan']

def loop_in_period_interval():
    PERIOD = 30
    ioloop = tornado.ioloop.IOLoop.current()
    ioloop.add_timeout(time.time() + PERIOD, loop_in_period_interval)
    trends = []
    for idx, trend in enumerate(api.trends_place(JP)[0]['trends'], 1):
        value = {
            "rank": str(idx),
            "name": trend["name"],
            "volume": trend["tweet_volume"],
            "url": trend["url"]
        }
        trends.append(value)
    TwitterTrendWebSocketHandler.trends_cache = trends
    json_str = json.dumps(trends)
    TwitterTrendWebSocketHandler.send_updates(json_str)

loop_in_period_intervalで30秒間隔でトレンドを取得しています。
なお、この部分はこちらを参考にさせていただきました。

クライアントにプッシュ

app.py
class TwitterTrendWebSocketHandler(tornado.websocket.WebSocketHandler):
    waiters = set()
    trends_cache = []

    def get_compression_options(self):
        return {}

    def open(self):
        TwitterTrendWebSocketHandler.waiters.add(self)
        trends = json.dumps(
            TwitterTrendWebSocketHandler.trends_cache
        )
        self.write_message(trends)

    def on_close(self):
        TwitterTrendWebSocketHandler.waiters.remove(self)

    @classmethod
    def send_updates(cls, trends):
        logger.info("sending message to %d waiters", len(cls.waiters))

        for waiter in cls.waiters:
            try:
                waiter.write_message(trends)
            except:
                logger.error("Error sending message", exc_info=True)

websocketのhandlerです。
接続時にopenメソッドでクラス変数waitersにクライアントが追加されます。
先程のloop_in_period_interval関数内でクラスメソッドsend_updatesが実行され各クライアントにブロードキャストされます。

app.py
if os.getenv("HEROKU") is None:
    dotenv_path = os.path.join(os.path.dirname(__file__), ".env")
    load_dotenv(dotenv_path)
    port = 8888
else:
    port = int(os.environ.get("PORT", 5000))

CONFIG = os.environ

HEROKUを使うにあたって.envファイルで環境変数を切り替えています。
また、こちらのプラグインを使うとheroku config:pushコマンドでローカルの.envファイルの内容をHEROKUの環境変数に設定できるのでおすすめです。

クライアントサイド

単純なアプリなのでvue-cliを使わずCDNを使っています。
その際、注意すべき点として記法の衝突があります。
Tornadoのテンプレートで使う{{}}がVueのマスタッシュ記法と同じになってしまいエラーが発生します。

app.js
const vm = new Vue({
  el: '#app',
  // 略
  delimiters: ["<%","%>"], //{{ }} から <% %>に変更
})

なので、このようにVue側でデリミタを変更する必要があります。

リストレンダリングにトランジションを追加する

テーブルに適用する際

index.html
<transition-group tag="tbody" id="left">
  <!-- 1 to 25 -->
    <tr v-for="trend in upTo25" :key="trend.name" v-cloak>
      <th><% trend.rank %></th>
      <td><a :href="trend.url" class="has-text-grey-darker"><% trend.name %></a></td>
      <td><% trend.volume %></td>
    </tr>
 </transition-group>

公式サイトにあるように、transition-groupタグを使い、tagtbodyを指定したのですが動作しませんでした。

index.html
<tbody is="transition-group" id="left">
  <!-- 1 to 25 -->
    <tr v-for="trend in upTo25" :key="trend.name" v-cloak>
      <th><% trend.rank %></th>
      <td><a :href="trend.url" class="has-text-grey-darker"><% trend.name %></a></td>
      <td><% trend.volume %></td>
    </tr>
</tbody>

こうすることでうまく動作しました。

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
No 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
ユーザーは見つかりませんでした