React Router v4 でルーティング先の component に Props を渡す方法
「React Router v4 でルーティング先の component に Props を渡す方法」について調査したので記事にします。
基本的なReact Router v4 の基本的なルーティング
React Router v4 の基本的なルーティングは次のような感じでコーディングします。
import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; ReactDOM.render(( <BrowserRouter> <AppFrame /> </BrowserRouter> ), document.getElementById('root'), ); class AppFrame extends Component { render() { return ( <main> <Switch> <Route path='/login' component={Login} /> <Route path='/getbook' component={GetBooks} /> <Route path='/addbook' component={Addbook} /> </Switch> </main> ); } }
今回は “component={xxxx}” で起動する React component に props を渡す方法を考えます。
React component に props を渡す
変数を props として渡す方法
上記 /getbook の URI でルーティングされる GetBook component に、ある変数(ここでは書籍ID(bookID)とします) を props として渡したい!となった場合、、その時は、以下のように書くと良いでしょう。
class AppFrame extends Component { render() { this.bookId = 2; // とりあえず仮に書籍ID = 2 と設定 return ( <main> <Switch> <Route path='/login' component={Login} /> // GetBook component に、bookID を props として渡します <Route path='/getbook' render={props => <GetBook bookId={this.bookId} {...props} />} /> <Route path='/addbook' component={Addbook} /> </Switch> </main> ); } }
“component” ではなく “render” を使うところがミソですね。
function を props として渡す方法
続いて、/login の URI でルーティングされる Login component に、認証処理を行う function auth() を props として渡たしたい!となったらどうするか?
同じく render を使用して渡してあげれば大丈夫です。
class AppFrame extends Component { auth(userInfo) { // 何かの認証処理 } render() { return ( <main> <Switch> // Login component に、認証処理を行う function auth() を props として渡します <Route path='/login' render={props => <Login onSubmit={userinfo => this.auth(userinfo)} {...props} />} /> <Route path='/getbook' component={GetBooks} /> <Route path='/addbook' component={Addbook} /> </Switch> </main> ); } }
参考となった情報
いろいろ調査しましたが、特に、下記の Github issue が参考になりました。様々なアプローチが議論されており見るだけで勉強になります。
まとめ?
最近、React Router が V4 になっていろいろ変わって大変だ!との嘆きを耳にしました。ですが、React 初心者である私は「へー」とか「ふーん」と実感も伴わずに聞き流していましたが、最近、実際にコードを書く段になって「大変」の意味がわかりました。
今回の調査もそうでしたが、とにかくまだ情報が少なく、あっても英語なことが多いので、どうしても時間がかかってしまします。また、v4に関する情報かどうかを見極めるのも(特に初心者は v2 や v3 の情報と混同しがち)以外に大変だったりしました。
ということで「英語は重要だ!」というまとめを以って終了です。
React 始めたので vim の jsHint を ESLint に変更した話
いまさらですが、React 書き始めました。すると、これまで利用していた jsHint ではエラーや警告が誤検出されるので、この対策をした時のメモになります。
React なら ESLint ですわ
React は JSX など独特な書き方がありますし、これからは ES6 になりますので、これらをうまく解釈できるものはないか? と調査すると jsHint で JSX をチェックする JSXHint というラッパーがありました。
よし、これを試すか、、と思ったらのっけから
Don’t use JSXHint anymore if you can switch to ESLint.
ということで、これまでお世話になった jsHint を辞めて ESLint に Switch しましょう。どうも現代では、React で書くなら ESLint を使うのが当たり前のようです。*1
ESLint セットアップ
私の開発環境(MAC OS Sierra)に ESLint を導入します。
導入方針
ESLint についていろいろ調べたところ、グローバルにインストールするのではなく、アプリケーション毎にローカルにインストールして、それぞれ専用の設定をして使用することができるようです。確かに、React 使う時や Angular 使う時やその他でコンフィグレーション内容が大きく変わりそうなので、ローカルにインストールする方が理に適っています。
また、ESLint がローカルにインストールされていれば、それをグローバル的に利用可能とする “eslint-cli” というツールを発見、便利そうなのでこれも併せて導入します。
(1) ESLint をローカルにインストール
前提として node.js がインストールされている必要があります。ちなみに、私の場合は、nodebrew で利用する node.js のバージョンを選択できるようにしています。
$ node -v v7.8.0 $ npm -v 4.2.0
以下のようにローカルに ESLint をインストールします。今回 React が前提なので eslint-plugin-react も必要となります。
$ npm install --save-dev eslint eslint-plugin-react
ちなみにインストールした ESLint のバージョンは 3.19.0 でした。
$ eslint -v v3.19.0
(2) ESLint 初期設定
ESLint を使用するには、予めルールなどを定義した設定ファイルを作成する必要がありますが、自作するのは結構メンドくさそうです。ですが最近では “eslint –init” で簡単に設定ファイルを作成できるようです。
というか、本家の Getting Start のページを見ると、むしろこの手順で初期化することが前提となっていますね。
Getting Started with ESLint - ESLint - Pluggable JavaScript linter
さっそくやってみましょう。
今回は対話(質問に答える)形式で初期化する方法で実行してみました。
$ ./node_modules/.bin/eslint --init ? How would you like to configure ESLint? Answer questions about your style ? Are you using ECMAScript 6 features? Yes ? Are you using ES6 modules? Yes ? Where will your code run? Browser ? Do you use CommonJS? No ? Do you use JSX? Yes ? Do you use React? Yes ? What style of indentation do you use? Spaces ? What quotes do you use for strings? Single ? What line endings do you use? Unix ? Do you require semicolons? Yes ? What format do you want your config file to be in? JavaScript Successfully created .eslintrc.js file in /Users/naoki/DEV/SANDBOX/react
成功です。下記のようにESLint の設定ファイル “.eslintrc.js” ができています。
$ cat .eslintrc.js module.exports = { "env": { "browser": true, "es6": true }, "extends": "eslint:recommended", "parserOptions": { "ecmaFeatures": { "experimentalObjectRestSpread": true, "jsx": true }, "sourceType": "module" }, "plugins": [ "react" ], "rules": { "indent": [ "error", 4 ], "linebreak-style": [ "error", "unix" ], "quotes": [ "error", "single" ], "semi": [ "error", "always" ] } };
(3) eslint-cli をグローバルにインストール
ここで、冒頭で説明した “eslint-cli” をインストールしておきます。これで、わざわざ “./node_module/.bin/eslit” とせずに “eslint” だけで実行できるようになります。
$ mpn install eslint-cli -g
(4) ESLint の動作確認テスト
ESLint 実行環境が整ったので動作確認します。テスト対象としたコードは、React Tutorial で作成した “index.js” です。
$ eslint src/index.js /Users/naoki/DEV/SANDBOX/react/src/index.js 5:10 error 'Square' is defined but never used no-unused-vars 6:3 error Expected indentation of 4 spaces but found 2 indent 13:7 error 'Board' is defined but never used no-unused-vars 14:3 error Expected indentation of 4 spaces but found 2 indent 15:5 error Expected indentation of 6 spaces but found 4 indent 17:3 error Expected indentation of 4 spaces but found 2 indent 18:5 error Expected indentation of 6 spaces but found 4 indent 40:7 error 'Game' is defined but never used no-unused-vars 41:3 error Expected indentation of 4 spaces but found 2 indent 42:5 error Expected indentation of 6 spaces but found 4 indent ... 省略 ... 128:5 error Expected indentation of 6 spaces but found 4 indent 129:5 error Expected indentation of 6 spaces but found 4 indent 130:7 error Expected indentation of 8 spaces but found 6 indent 133:3 error Expected indentation of 4 spaces but found 2 indent ✖ 48 problems (48 errors, 0 warnings)
ご覧の通りたくさんのエラーが出てしまいました。よく見ると、そのほとんとがインデント数が変だと言っていますが、これは誤検出です。むしろ設定ファイルのタブ数の設定に問題がありますので “.eslintrc.js” の “rules.indent” を 4 から 2 に変更します。
"indent": [ "error", 2 ],
再度実行してみます。
$ eslint src/index.js /Users/naoki/DEV/SANDBOX/react/src/index.js 5:10 error 'Square' is defined but never used no-unused-vars 13:7 error 'Board' is defined but never used no-unused-vars 40:7 error 'Game' is defined but never used no-unused-vars ✖ 3 problems (3 errors, 0 warnings)
だいぶマシになりましたが、3箇所エラーが検出されてしまいました。うむむ。
こちらは ES6 のプログラム的には問題ない(never used となっていますが JSXから参照しています)ので、やはり ESLint の誤検出で、設定に問題があります。
(5) no-unused-vars 問題を解決する
こちらに解決策がありました。ありがたや。
また、eslint-plugin-react のページでも、no-unused-vars を prevent するルールについての記述がありますね。
ということで、次のルールを “.eslintrc.js” に加します。
"rules": { "react/jsx-uses-react": "error", "react/jsx-uses-vars": "error", }
これで再実行して Lint エラー(誤検出)が全て無くなりました。OKです。
vim のチェッカを jsHint から ESLint に変更
最終的な目的は、vim で自動的に Lint チェックしてもらうことなので、.vimrc の設定を変更します。
具体的には、下記の通り “let g:syntastic_javascript_checkers” の値を “jshint” から “eslint” に変更するだけです。
let g:syntastic_mode_map = { 'mode': 'active', \ 'active_filetypes': [], \ 'passive_filetypes': [] } let g:syntastic_javascript_checkers = ['eslint'] let g:syntastic_check_on_wq = 0
これで、vim で編集する javascript の コードは、ESLint でチェックすることが可能となりました。これでとりあえずの作業は全て完了です。
まとめ
- React なら ESLint を使え
- ローカルインストールすれば、アプリケーション毎に専用の設定ができる
- ESLint の設定ファイルを一から自作するのはちょっと大変だが、"eslint –init" でこの作業を簡単にすることができる
今回はこれくらいです。 これからは ES6 必須ですし、しばらくは ESLint のお世話になりそうです。ということは、さらにきめ細かな設定方法や、様々なツールやエディタとの連携方法なども習得していく必要がありますね。
*1:世間の速さに追いついていないです。キャッチアップしないとだめです
Ruby で カウントダウン Twitter BOT 作って Scaleway の Docker で動かす- 後半(完成まで)
大事な日までのカウントダウンを毎日 tweet してくれる BOT を Ruby で作成して Scaleway サーバで動かそうと思います。こんな感じでつぶやきます。
Hi! just 432 days left until the Special Day.
— Naoki Nagazumi (@nk_ngzm) 2017年4月25日
前半のおさらい
このエントリは、先日書いた以下の記事の続きです。
前半は下記のことを行ないました。
- カウントダウン Twitter BOT を Ruby で作成しました
- Scaleway に Docker コンテナが動く仮想サーバを立てました
- 上記仮装サーバの Docker 上で Ruby:latest コンテナが動くことを確認しました。
今回はその続きで、実際に Scaleway の Docker で動かすまでの話です。
カウントダウン Twitter BOT の Docker コンテナを作成
1) Docker Ruby イメージについて
まず最初は、今回の Docker コンテナのベースとなる Ruby イメージについて、その基本的な使い方や構成などを確認しておく必要があります。これらは、 DockerHub の Ruby ページ で確認できます。
どうも Ruby アプリケーションは /usr/src/app/ にデプロイして動かせば良いようです。
2) Dockerfile などコンテナ環境の準備
さて、Twitter BOT アプリケーション用の Docker イメージを作成するための Dockerfile を作成します。
今回、この Docker ファイルは、Twitter BOT アプリケーション(countdown_bot.rb など)と同じディレクトリに作成しました。
FROM ruby:latest MAINTAINER ngzm<nk.ngzm@gmail.com> ADD . /usr/src/app RUN cd /usr/src/app && bundle install RUN cd /usr/src/app && chmod u+x countdown_bot.sh CMD ["/usr/src/app/countdown_bot.sh"]
countdown_bot.sh というのはこのアプリを起動するだけの簡単なシェルスクリプトです。次のような感じです。これもアプリケーションと同じディレクトリに保存します。
#!/bin/bash cd /usr/src/app if [ $? -eq 0 ]; then ruby countdown_bot.rb fi
なお、作成した Docker ファイルや、起動スクリプト countdown_bot.sh は、アプリケーションコードと同様、github のページ に置いてありますので適宜参照してください。
3) Docker コンテナを作成
準備が完了したので、docker build で Twitter BOT アプリケーション用の Docker イメージを作成します。
# docker build -t countdown . Sending build context to Docker daemon 68.61 kB Step 1 : FROM ruby:latest ---> d2cee8adb148 Step 2 : MAINTAINER ngzm<nk.ngzm@gmail.com> ---> Using cache ---> 276ca2d970a3 Step 3 : ADD . /usr/src/app ---> f7a2c4909d42 Removing intermediate container 8730da1e725f Step 4 : RUN cd /usr/src/app && bundle install ---> Running in 7895f7170efc Fetching gem metadata from https://rubygems.org/........ Fetching version metadata from https://rubygems.org/.. Fetching dependency metadata from https://rubygems.org/. Installing public_suffix 2.0.5 Installing buftok 0.2.0 Installing unf_ext 0.0.7.4 with native extensions Installing equalizer 0.0.11 Installing multipart-post 2.0.0 Installing http-form_data 1.0.1 Installing http_parser.rb 0.6.0 with native extensions Installing thread_safe 0.3.6 Installing naught 1.1.0 Installing simple_oauth 0.3.1 Using bundler 1.14.6 Installing addressable 2.5.1 Installing unf 0.1.4 Installing faraday 0.11.0 Installing memoizable 0.4.2 Installing domain_name 0.5.20170404 Installing http-cookie 1.0.3 Installing http 2.2.1 Installing twitter 6.1.0 Bundle complete! 1 Gemfile dependency, 19 gems now installed. Bundled gems are installed into /usr/local/bundle. ---> 6842c8ee3be4 Removing intermediate container 7895f7170efc Step 5 : RUN cd /usr/src/app && chmod u+x countdown_bot.sh ---> Running in b14e152beca3 ---> b581ef596c71 Removing intermediate container b14e152beca3 Step 6 : CMD /usr/src/app/countdown_bot.sh ---> Running in 28768d88b292 ---> 40c6fe50a43f Removing intermediate container 28768d88b292 Successfully built 40c6fe50a43f
成功です。Twitter BOT アプリケーションファイルをコピーして、bundle install もうまく行っていますね。docker images で確認すると、きちんとDocker イメージが生成されていました。
続いて、 Docker イメージから、Docker コンテナの作成 + 起動を行います。
# docker run --name countdown_bot countdown
エラーなく終了しました。ここで Twitter を見てみると、無事につぶやきが投稿されていました。OKです。カウントダウン Twitter BOT の Docker コンテナができました。
cron で定期的に実行させる
ここまできたら、後は、カウントダウン Twitter BOT コンテナを、定期的に自動実行できれば良い訳です。とりあえず、今回は、cron に仕込んで実行させることにします。
# crontab -e 0 9 * * * docker start countdown_bot
私の生活リズム都合で、毎朝 9時につぶやいてもらうように設定しました。
その後追記
と言う訳で、翌日の朝9時になりました。が、その時間になっても一向につぶやきませんでした。むむむ。
どこか不具合があったかぁ、、と考えたら、はっと問題点に気づきました。私がセットしたのは確かに 9:00AM ですが、それは日本時間ではありません。そうです Scaleway サーバは Paris にあるのです。早速サーバにログインして、タイムゾーンを確認すると UTC でした。なるほど。
ということで対策を行います。今回は、せっかくUTCで動いているので、タイムゾーンはそのままで、Twitter BOT アプリケーションの起動時間を -9時間するように cron を設定し直しました。
# crontab -e 3 0 * * * docker start countdown_bot
なお、ジャスト0時に起動するのもなんなので*1、0時3分に起動するようにして完了です。翌日 9時3分に無事につぶやきを確認してとりあえずおしまいデス。
まとめ
- Scaleway の VC1s + Docker で Ruby アプリケーションが割と簡単に動かせる
- 海外のサーバは JST じゃない(当然ですが)ので気をつけろ
- 毎朝 9時3分にこのつぶやきを見ながら、その日に向かってしっかり頑張ろう!!
*1:経験的にこのような境界値に思わぬ問題が潜んでいることが多いので、今回は簡単に少しだけずらしてリスクを回避します
Ruby で カウントダウン Twitter BOT 作って Scaleway の Docker で動かす- 前半(ただしWIP)
大事な日までのカウントダウンを毎日 tweet してくれる BOT を Ruby で作成して Scaleway サーバで動かそうと思います。こんな感じでつぶやきます。
Hi! just 432 days left until the Special Day.
— Naoki Nagazumi (@nk_ngzm) 2017年4月25日
モチベーション
どうしてそんなものを作る気になったのか?とか「大事な日」とは何の日なの?とかは、いろいろあって、ここでは公にできないのですが、とりあえず、その日までの過ごし方が重要なので「その日に向かって日々頑張ろう!!」的な気持ちを継続するために、本 BOT に毎日つぶやいてもらいます。
また Scaleway とはフランスの格安サーバ会社で、ベアメタルなサーバが 日本円で 400円/月くらいからレンタルできるのが特徴です。2年ほど前に kawasaki.rb の LT で教えてもらって気になっていたやつです。
今回はサーバ上の Docker コンテナにアプリを入れて動かすつもりです。
Twitter Bot の作成
Ruby では twitter という Gem があって、これを利用すればあっさりと実現できます。以下、簡単に実装の流れを説明します。
1)Twitter API 利用するアプリケーション登録
Twitter に投稿するためには Twitter API を利用する必要がありますが、そのためには、アプリケーション登録をする必要があります。ということで、さっそく Twitter developers へログインしてアプリケーション情報を登録します。
注意点として、今回はTwitter 投稿するので、Access Level を “Read and write” にしておく必要があります。
アプリの情報が登録できたら、アプリが利用する Twitter API の認証と認可に必要な Consumer の情報と Access Token の情報を取得できます。
具体的には、下記の4つの情報をコピーします。
2)Twitter Bot のコーディング
twitter Gem を使用した Twitter 投稿処理は、次のコードが基本となります。
require 'twitter' client = Twitter::REST::Client.new( consumer_key: 'YOUR-CONSUMER-KEY', consumer_secret: 'YOUR-CONSUMER-SECRET', access_token: 'YOUR-ACCESS-TOKEN', access_token_secret: 'YOUR-ACCESS_TOKEN_SECRET' ) client.update 'Some Tweet Message ...'
consumer_key、consumer_secret、access_token、access_token_secret の各値は、Twitter developers で登録したアプリケーションの情報をセットしてください。
私の場合は、大事な日までのカウントダウンを呟いてもらわなくてはなりませんので、その辺りも含めて(現在)以下のコードになってます。
require 'twitter' require 'date' require 'yaml' # SayTwitter class Tweeter def initialize(config) @config = config end def say(message) client = Twitter::REST::Client.new( consumer_key: @config['tweet']['consumer_key'], consumer_secret: @config['tweet']['consumer_secret'], access_token: @config['tweet']['access_token'], access_token_secret: @config['tweet']['access_token_secret'] ) client.update message end end # Countdown Class class CountDown def initialize(config) @config = config end def post the_day = Date.new(@config['theday']['year'], @config['theday']['month'], @config['theday']['day']) boring_days = (the_day - Date.today).to_i # Say to Twitter message = "Hi! just #{boring_days} days left until the Special Day." yield message end end # Load CONFIG FILE CONFIG_FILE = 'countdown_bot.yml'.freeze config = YAML.load_file(CONFIG_FILE) countdown = CountDown.new(config) tweet = Tweeter.new(config) # Tweet Count Down Message countdown.post do |message| tweet.say message end
consumer_key、consumer_secret、access_token、access_token_secret などの情報は、外部 YAML ファイルで定義するようにしています。コード全体は、github のページ を参照してください。
Scaleway サーバの作成
アプリは作成できたので、これを動作させるサーバを Scaleway 上に準備します。前提として、今回も 400円/月 の範囲で活用したいと思います。
1)C1 サーバ + docker イメージで試してみる
まずは、Scaleway の C1 という ARM CORE のベアメタルサーバで一番チープな構成(400円/月)で試してみます。
サーバで稼働するOSイメージは、ubuntu などメジャーなデストリビューションから選択できます。
また、あらかじめミドルウェアまで入ったOSイメージも用意されています。こうなると PaaS みたいです。
今回は、Docker コンテナでアプリを動かすので、OSのイメージは Dokcer を選択してオーケストレーションします。こうして、しばらくするとマシンが立ち上がってきました。起動できたので、次は Docker コンテナを作成しますが、とりあえず Docker -v でバージョンを確認すると Version 1.12 でした。現在の最新版が 1.17 系なので、ちょっと古いですね。
続いて、ruby:latest イメージを pull して、docker run してみます。するとナゾの go-lang エラーがばんばん出ました。
# docker run --rm -it ubuntu:trusty panic: standard_init_linux.go:175: exec user process caused "exec format error" [recovered] panic: standard_init_linux.go:175: exec user process caused "exec format error" goroutine 1 [running, locked to thread]: panic(0x3339c8, 0x10747800) /usr/local/go/src/runtime/panic.go:481 +0x330 github.com/urfave/cli.HandleAction.func1(0x107c5958) /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:478 +0x328 ... ... 以下省略 ...
よく見ると、Docker コンテナのフォーマットエラーとか何とか書いてあります。とにかくうまく動きません。
2)C1 サーバ + ubuntu イメージで試してみる
どうもダメなので、一旦サーバを破棄して、C1 サーバ + ubuntu xenial (16.04 LTS) イメージ でサーバを作って、そこに Docker を入れて試してみます。無事に Docker のインストールまで完了したので、 そのバージョンを確認すると Version 1.17 最新版です。
まずは、Docker の動作確認用コンテナ “Hello World” で動作確認してみます、すると、さっきと同様に go-lang のエラーが発生!それでも、あきらめずに、ruby:latest イメージで docker run してみますと、やっぱりエラーとなりうまく動きませんでした。
3)C1 サーバ の問題
どうしてもダメなので、C1 サーバのドキュメントをちゃんとみて見ると、その CPU は「ARM v7」であると書いてありました。
「ARM v7」って?さらに調べたところ、どうやら 32bit CPU らしき情報を発見!なるほど、32 bit なら docker は動かないですね。この事実が分かるまで2〜3時間かかってしまいました。
せっかくのベアメタルサーバなのに、これでは目的が達成できなません。ちなみに、これより上位の構成(当然お金も高くなる)であれば、64bit のCPUを採用しているので、あとは金で解決するか・・いや止めよう
4)VC1s サーバ + docker イメージで試してみる
Scaleway はベアメタルなサーバ以外にも、一般的な仮装サーバの提供も行なっており、それであれば、約400円/月 かつ 64bit の環境が使えます。
ということで、ベアメタルサーバは諦め、仮装サーバ VC1s での実現を目指します。OSイメージはとりあえず Docker で行きます。
と、無事にマシンが起動できました。そこで、先ほどと同様 “Hello World” コンテナで動作確認をしてみると無事に成功しました。今度は大丈夫そうです。 ということで、ruby:latest イメージを pull して docker run で Ruby コンテナを実行させると、きちんと irb が起動しました。
# docker run --rm -it ruby:latest irb(main):001:0> irb(main):002:0* puts "Hello!!" Hello!! => nil
とりあえず、現在はここまでの状況です。明日以降で Ruby で作成した Twitter BOT を Scaleway のVC1s サーバ + Docker に乗せて動かす作業を行います。
ここまでのまとめ
- twitter Gem を使うと簡単に Ruby で Twitter API 使えそう
- Scaleway サーバで Docker を動かすなら C1 サーバは使えない
- 大事な日まで心折れずにがんばろう
後半につづく
2017/4/30 - 後半の記事を書きましたのでお知らせいたします。
macOS Sierra にしたら photoanalysisd というプロセスでホットになった
Sierra にしてしばらく遊んでたら、どうも常時CPU使用率が7割以上回っている様子で、MAC BOOK がホットになったので、どのプロセスが原因なのか見てみました。
どうも photoanalysisd というプロセスですね。
検索してみると、なるほど 「photoanalysisd 暴走」 というタイトルの記事がたくさんありました。どうやら、一時中断もできるが、しばらく放っておくとそのうちおさまるとの噂です。ならばと、そのまま数日間放置していたら、なんとなく静かになりました。
と安心したのも束の間、続いて mediaanalysisd という第二の刺客が現れ、こいつは4割くらい CPU を占有するようになりました。私はあまり動画とか保存していなかったのもあってか、mediaanalysisd の暴走は数時間で解消しました。
ということで今ここ。次は 何analysisd が暴走するのだろうか?