Reactでクエリパラメーターが変更された場合のリソースの更新する方法
どうも、くずきです。
React
でクエリパラメーターが変更された際にどうやってリソースの更新をするかについて書きたいと思います。
当たり前だがreact-router
ではhogehoge.com
とhogehoge.com?sort=abc
は同じコンポーネントと認識されるため、画面の再描画などは行われない。
そこで、クエリパラーメーターが変更されるたびにリソースの更新する実装してみた。
componentWillReceivePropsを使った更新
React
には、componentWillReceiveProps
といわれるprops
が更新されるたびに呼ばれる関数がある。
react-router
を使っているならば、クエリパラメーターに変更があった場合もここが呼ばれるみたいだ。
これがわかってしまえばすごく簡単。
componentWillReceiveProps(nextProps) { if (nextProps.location.search !== this.props.location.search) { // Actionから新しいリソースを取得しに行く Action.get(nextProps.location.search); } }
このように、次のprops
のlocation.search
を比較することで更新するかしないかを決めることができる。
簡単なんですけどグーグル先生でパッと検索できず、実は他の簡単なやり方を皆は使ってるんじゃないかと思ってるので知ってたらご連絡くだせい。。
ReactのEventEmitterで登録したリスナが削除できない問題の解決法
どうも、くずきです。
EventEmitter
で登録したリスナが削除できない問題について解決した方法をメモしときたいと思います。
構成
- EventEmitter
- ErrorStore(
EventEmitter
を継承したクラスをStore
として利用) - サーバーサイドから取得したエラーを登録したリスナに通知
- ErrorStore(
- Component
- App.js
- エラー時の関数を
EventEmitter(Store)
に登録する
EventEmitter
本記事では書いてないが、Action
でサーバー側に通信した後エラーだった場合に呼ばれるStore
。
this.on
で通知するリスナを登録している。
class ErrorStore extends EventEmitter { handleActions(action) { if(action.type === "ERROR"){ // エラー通知 if(action.res.hasOwnProperty("statusCode")) { switch (action.res.statusCode) { case 500: break; case 400: this.emit(EVENT.ERROR.VALIDATION, action.res.body.errors); break; case 401: this.emit(EVENT.ERROR.AUTHENTICATION, action.res); break; default: break; } } } } addValidListener(listener) { this.on(EVENT.ERROR.VALIDATION, listener); } removeValidListener(listener) { this.removeListener(EVENT.ERROR.VALIDATION, listener); } addAuthListener(listener) { this.on(EVENT.ERROR.AUTHENTICATION, listener); } removeAuthListener(listener) { this.removeListener(EVENT.ERROR.AUTHENTICATION, listener); } } const errorStore = new ErrorStore(); dispatcher.register(errorStore.handleActions.bind(errorStore)); export default errorStore;
初期のComponent
一番初期(問題があるとき)につくったコンポーネント。
handleError
関数をErrorStore
のaddValidListener
でリスナに登録している。
class App extends Component { constructor(props) { super(); this.state = { errors: null }; } componentWillMount() { errorStore.addValidListener(this.handleError.bind(this)); } componentWillUnmount() { errorStore.removeValidListener(this.handleError.bind(this)); } handleError(_errors) { // エラーの内容を解析する関数を呼ぶ let errors = Validation.getValidationErrors(_errors); this.setState({ errors: errors }); } render() { if (this.state.errors) { .... } } }
当初はcomponentWillUnmount
で既に登録したリスナ(this.handleError.bind(this)
)を消すはずが
Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the undefined component.
というエラーを吐き、できなかった。
EventEmitter
のコードを追い、removeListenerで消す条件を確認したところ、関数同士を比較してるようだ。
実際にthis.handleError.bind(this) === this.handleError.bind(this)
を行なったところfalse
になり、bind
した関数同士はイコールにならないみたい。
bind関数の仕様をみると、確かに関数を新たに作成してるっぽいのでこれはイコールにはならない。。。
改善版Component
ここまで分かればもう簡単で、コンストラクタでbind
した関数を保持し、それを利用すれば良い。
class App extends Component { constructor(props) { super(); this.state = { errors: null }; this.handleError = this.handleError.bind(this); } componentWillMount() { errorStore.addValidListener(this.handleError); } componentWillUnmount() { errorStore.removeValidListener(this.handleError); } handleError(_errors) { // エラーの内容を解析する関数を呼ぶ let errors = Validation.getValidationErrors(_errors); this.setState({ errors: errors }); } render() { if (this.state.errors) { .... } } }
これでエラーも消えてめでたしめでたし。
ただjavascript
はこういったエラーを気にしないと気付かずバグをうんだりするので、もっと理解しないとなと思います。
Docker Compose + LaravelをCircleCI2.0上でテストする
どうも、くずきです。
こないだ久々にCircleCI
を使ったらバージョンが上がってたのとdocker-compose
を使ったやり方が変わっていたので、とりあえずテストまでできたレベルメモっておきます。
各バージョン
- Dokcer(for MacOS)
- Docker version 17.03.1-ce, build c6d412e
- docker-compose
- docker-compose version 1.11.2, build dfed245
- Laravel
- 5.5.11
- PHP
- 7.1.1
- Mysql
- 5.7
- CircleCI
- 2.0
※ 今回アプリケーションとしてLaravel
使うけど、構築などの説明はしないです。
Dockefileの設定
すでにLaravel
のアプリケーションがある前提で、さっさと構築。
FROM php:7.1.1-apache RUN a2enmod rewrite RUN set -ex \ && buildDeps=' \ libfreetype6-dev \ libjpeg62-turbo-dev \ libpng12-dev \ ' \ && apt-get update \ && apt-get install -y --no-install-recommends \ $buildDeps \ libmcrypt-dev \ libicu-dev \ curl \ zip \ unzip \ && rm -rf /var/lib/apt/lists/* \ && docker-php-ext-configure \ intl \ && docker-php-ext-install \ pdo_mysql \ mysqli \ mbstring \ gd \ iconv \ mcrypt \ intl \ && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \ && apt-get purge -y --auto-remove $buildDeps COPY php.ini /usr/local/etc/php/
Dockerfile
として、アプリケーションのルートディレクトリに配置。
目新しいことはしてない一般的なphp
周りの設定。
docker-compose.ymlの設定
docker-compose.yml
を以下のように書く。
version: '2' services: datastore: image: busybox volumes: - /var/lib/mysql db: image: mysql:5.7 command: > bash -c ' mkdir /var/log/mysql && touch /var/log/mysql/general.log && chown mysql:mysql /var/log/mysql/general.log && tail -f /var/log/mysql/general.log & /entrypoint.sh mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --general-log=true --general-log-file=/var/log/mysql/general.log ' environment: - MYSQL_ALLOW_EMPTY_PASSWORD=true - MYSQL_DATABASE=[データベース名] ports: - "3333:3306" volumes_from: - datastore cache: image: redis:3.2.3-alpine ports: - "6379:6379" app: build: . ports: - "8000:80" volumes: - .:/var/www/html - ./000-default.conf:/etc/apache2/sites-available/000-default.conf depends_on: - db - cache
Dockerfile
と同じくルートディレクトリに配置。
ここも特に目新しいことはしてないが、mysql.log
を常にtail
したかったので、いらない人はその部分を消してもらえると良いです。
一応apache
の000-default.conf
も載せておく。
<VirtualHost *:80> DocumentRoot /var/www/html/public <Directory "/var/www/html/public"> AllowOverride All </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
CircleCI用の.envファイルの設定
APP_NAME=Laravel APP_ENV=local APP_KEY= APP_DEBUG=true APP_LOG_LEVEL=debug APP_URL=http://localhost DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=[データベース名] DB_USERNAME=root DB_PASSWORD= BROADCAST_DRIVER=log CACHE_DRIVER=file SESSION_DRIVER=file QUEUE_DRIVER=sync REDIS_HOST=cache REDIS_PASSWORD=null REDIS_PORT=6379 MAIL_DRIVER=smtp MAIL_HOST=smtp.gmail.com MAIL_PORT=587 MAIL_ENCRYPTION=tls MAIL_FROM_ADDRESS= MAIL_FROM_NAME= MAIL_USERNAME= MAIL_PASSWORD= MAIL_PRETEND=false
CircleCI
用にLaravel
の.env.circle
ファイルの設定。
DB_HOST
とREDIS_HOST
はdocker-compose
で設定した名前を書く。
CricleCIの設定
最後に、CircleCI
の設定ファイルを.circleci/config.yml
に書く。
versin: 2 jobs: build: machine: true steps: - checkout - run: name: Setup docker command: | docker-compose build docker-compose up -d docker-compose run app composer install - run: name: Setup Laravel command: | cp .env.circleci .env docker-compose run app php artisan key:generate docker-compose run app php artisan migrate:refresh --seed - run: name: Run Test command: | docker-compose run app vendor/bin/phpunit
CircleCI2.0
の新機能であるworkflows
を使ってないので物足りなさがあるが、これで一通り設定できた。
CircleCI
での結果画面。
今後
今回の設定だと、そもそも毎回docker-compose
をビルドするせいで遅く、キャッシュさせる必要がある。
CircleCI2.0
だとsave_cacheとrestore_cacheを使えばできそうみたい。workflows
も含めて、次回へのお楽しみということで・・・。
とあるWebサービスの使用技術の調べ方
どうも、くずきです。
最近とあるWebサービスを知り合いと見ていて、
- このWebサービスってどういう技術使ってるんだろう?
- このグラフは何かライブラリ使っているのか?
と言っていたので、自分なりの調べ方について書いてみようかなと思います。
【結果】知りたい別の調べ方
やり方から書くと
- 大体ざっくりの使用技術わかる
- かなり重宝してる(というか見ていて面白い)
- 見えている部分の技術しかわからない
- StackShare
- 登録してくれてれば、見えない部分の技術も書いてくれてる
- 登録しない場合が多いので、あればラッキー
- 技術トレンド追う方にも使える
- ググル
- 基本ですね
- ThoughWorks Radar
- ThoughWorksがレポートで出している、技術トレンドみたいなやつ
- 使用技術を調べたいというより、その技術の立ち位置とか見やすい
- GithubTrend
余計なものも書いてしまいましたが大体Webサービスの技術で知りたいことってWappalyzer
あれば結構事足りること多いです。
Wapplalyzerの使い方
Chromeのプラグインで入れてしまえば終わり。
こないだUserLocal
のサイトで良さげなグラフがあったので、何使ってるんだろーと覗いて、そのまま採用した例です。
覗いて見ると、Javascript Graphics
のところのグラフっぽいライブラリのHighcharts
を見つけた。
あとはHighcharts
をググれば調査は終了。
もちろん対応していないライブラリなどは覗けないので・・・そこは割り切り。
どんなのが調べられるのかが気になる方は検知可能なアプリケーション一覧があるので見とくといいです。
StackShareの使い方
StackShareのサイトへ行き
検索窓からサービス名や会社名を打てばでてくる。 登録されてない場合はでないので・・・あきらめましょう。
自社のサービスをPR用に登録しておくのはありかもしれないですね。
(もしあったらお〜と自分はなります)
StackShareはトレンドを見れたりするので、そっちのほうが面白かったりする。 ただ、有名どころがやっぱり上位きてしまうので・・・、タグなどを掘り下げてみていくと色々見つかる。
ThoughWorks RadarとGithubTrend
この二つは技術トレンド追うだけのものなので・・・大きな流れを見る場合はThoughWorks Radar、ライブラリなどや流行を見たい場合はGithubTrendという使い方かなー。。今の所。
以上です。よくよく考えたら求人から追ったほうが早いですね。
react-routerを使ったルーティング処理
どうも、くずきです。
こないだ、create-react-appを本番環境で使ってみた(導入編)について紹介しました。
今回はreact-routerを使ったルーティング処理をやてみます。
バージョンは4.2.2
を利用。
バージョン3
の時とガラッと変わったみたいだけど、4
からなのであまり知りませぬ。
興味がある人は検索してみてくだせい。
そーろーな方は、ここみてください。
react-router-domの追加
packege.json
にreact-router-dom
を追加する。
Webサイト作る人はreact-router-dom
にしとけば問題ないと思う。
{ "name": "create-react-app-practice", "version": "0.1.0", "private": true, "dependencies": { "react": "^15.6.1", "react-dom": "^15.6.1", "react-router-dom": "^4.2.2", # 追加 "react-scripts": "1.0.13" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" } }
忘れずインストール
npm install
これで下準備は完了。
Routes Componentの追加
ルーティングの起点となるComponent
を作る。
まず、src
以下にRoutes.js
を追加する。
import React, { Component } from "react"; import { BrowserRouter, Route } from "react-router-dom"; import App from "./App"; export class Routes extends Component { render(){ return ( <BrowserRouter> <Route exact path="/" component={App}/> </BrowserRouter> ) } } export default Routes;
<BrowserRouter>
がルーティングするための肝となる部分で、
構築するサイトが静的なファイルのみで構成されてない
ならこれでいいと思う。
既に存在するApp(Component)
をインポートし、<Route>
でパスとコンポーネントを指定している。
index.jsで読み込まれるコンポーネントの変更
最後に、index.js
のApp
の部分を、先ほど作ったRoutes
に変更してあげれば完成です。
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import Routes from './Routes'; # 変更 import registerServiceWorker from './registerServiceWorker'; ReactDOM.render(<Routes />, document.getElementById('root')); # 変更 registerServiceWorker();
とりあえず終わり。
(おまけ)Switchを利用したNotFoundページの作り方
あまりに簡単すぎたので、もう少しreact-router
の機能を使ってみます。
react-router
にはSwitch
と呼ばれる排他的
にレンダリングする機能があります。
[参考]
github.com
ようは、path
にマッチしなかったらpath
がついてないコンポーネントを表示することができる。
src
以下にNotFound.js
を追加する。
import React, { Component } from "react"; class NotFound extends Component { render() { return ( <div clasName="NotFound"> <p><strong>ページが見つかりません。</strong></p> </div> ) } } export default NotFound;
ページが見つかりませんとでるだけのコンポーネント。
次にRoutes
に実装する。
import React, { Component } from "react"; import { BrowserRouter, Switch, Route } from "react-router-dom"; import App from "./App"; import NotFound from "./NotFound"; # 追加 export class Routes extends Component { render(){ return ( <BrowserRouter> <Switch> # 追加 <Route exact path="/" component={App}/> <Route component={NotFound}/> # 追加 </Switch> # 追加 </BrowserRouter> ) } } export default Routes;
実際に今回指定していないpath
でアクセスして見ると
このようにSwitch
の機能を使ったNotFound
の実装ができた。
以上です。
こちらのリポジトリで、今回の内容も含めて随時commit
していってます。
create-react-appを本番環境で使ってみた(導入編)
どうも、くずきです。くずさんって呼ばれるの目指してます。
React
経験0
の僕が、会社の新規WebアプリでReactを使った例をご紹介します。
Reactについての説明はまた後日にするとして、手を動かしながら理解していきましょう。
create-react-appとは?
React(というかフロントエンド)の課題として、一からの構築がなり大変なのは構築したことある方はお分かりかと思います。
Get Started Immediately
You don’t need to install or configure tools like Webpack or Babel. They are preconfigured and hidden so that you can focus on the code.
Just create a project, and you’re good to go.
READEMEから引用したもの。
TOEIC400点代の僕がやんわり略すと、「お前はコードを書くことに集中しろ」だ。 つまり、イニシャルの構築で必要なWebpackなどそういうのは俺がやっとくぜと・・・かなり粋な計らいですね。
実際にやってみましょう。 (ほとんど上記のgithubページのやり方なのでそちらみた方が早いっちゃ早い)
create-react-appのインストール
$ npm install -g create-react-app
npmでグローバルでインストールする。
$ npm -v 3.10.9
また、一応npm
のバージョンのせておきます。
Reactアプリの構築
次に、実際にアプリを構築していく。
$ create-react-app create-react-app-practice
色々インストールされる。
webpack
とかbable
とかフロントエンドで知ったような名前がでてきてます。
$ cd create-react-app-practice $ tree -L 2 -I 'node_modules' . ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json └── src ├── App.css ├── App.js ├── App.test.js ├── index.css ├── index.js ├── logo.svg └── registerServiceWorker.js
実際にフォルダに入って中身を見てみる。
ちょっとオシャレにみたいので、tree
コマンドを使うといい感じにみれますよ。
node_modsules
は余計なのがいっぱいなので省く。
Reactの起動
ここまでも簡単ですが、ここまできても簡単です。 フォルダに入った状態で、
$ npm run start
とやれば、勝手に http://localhost:3000
でReactのアプリが起動ができる。
index.js
でApp
Componentをよんでるだけなので、構築をとりあえず楽にしたって意外は特になんもしてないですね。
(おまけ)githubにあげる
せっかくなんであげよう。
フォルダに入った状態で
$ git init $ git remote add origin [自分のリポジトリURL] $ git add . $ git commit -m "create-react-appの導入編" $ git push origin master
以上で終わり。
こちらのリポジトリで、今後の内容も含めてcommitしていく予定〜〜。