Dockerコンテナ内でComposerコマンドを使えるようにするメモ
Dockerのコンテナ内でComposerを使おうとした時のメモです。
まず、何も考えずに「curl -sS https://getcomposer.org/installer | php」でComposerをインストールするとカレントディレクトリにcomposer.pharが置かれます。
もちろんこのままではcomposerコマンドが利用できません。
Composerコマンドを使えるようにするには「/usr/local/bin」配下にcomposer.pharを配置しなければならないのですが、ただ置いただけではComoserコマンドを利用することはできません。
そこで行うのが「/usr/local/bin」配下に置いた「composer.phar」のリネームです。
「mv composer.phar composer」として「composer」にリネームすることで、Composerコマンドが利用できるようになりました!
他にも「/usr/local/bin」配下にcomposerディレクトリを作る、という方法もあるらしいですが私はそれで対処できませんでした...
とりあえず、一番手っ取り早いのは
- 「/usr/local/bin」に移動
- 「curl -sS https://getcomposer.org/installer | php」を打つ
- 「mv composer.phar composer」でリネーム
という感じでしょうか。
上手くいかなかったら教えてください〜
JavaScriptでアプリを作る!React Nativeの環境を作ってみよう
「ちょっとReactでアプリ作れるっぽいんだけど触ってみてくんない?」というお言葉から、本日はReact Nativeをかるーく触ってみました!
以前Reactを触ってみたお話しをしましたが、React Nativeはアプリケーションを作るためのものという認識なので触れてなかったんですね...
hubarifront.hatenablog.com
ただ、やはり触ってみた所感としては「ReactはReactだ!」、そして「SwiftやJavaなどを使って本格的にアプリを作るのはちょっと億劫だなあ」というフロントエンジニアの方にはもってこいのフレームワークだなあと改めて実感したところであります。
ということで、今回はReact Nativeをかるーく触ったお話をしていきたいと思います!
React Nativeの環境を作る!
React Nativeの環境はどうやらReactとは少し違うよう。
なんせアプリ開発ですからね...
公式ドキュメントを見る限り大雑把に分けると二つの方法にわかれます。
1. 「npm install -g create-react-native-app」で一発
2. nodeとwatchmanをbrew install、react-native-cliをnpm installしてprojectをinitする方法
まあReactの環境構築と似たような感じですね。
前回Reactでプロジェクトを作成したときは2の方法をとって、一から作っていたので今回は1の提供されているデフォルトのプロジェクトをインストールする方法をとりました。
本来ならつまづくところではないのですが、わたくしここでつまづきました....
というのも最近Macの様子がおかしく、時々Homebrewの挙動がやばいんですよね(笑)
まず、「npm install -g create-react-native-app」は問題なく入りました。
次に、「create-react-native-app プロジェクト名」でプロジェクトを作るのですが、ここも問題なかったです。
この二点を実行することでReact Nativeを動かす要素は揃ったはずだったのですが、「npm start」をすると「watchmanを入れるように」というエラーが。
ここで「brew install watchman」を打ったのですが、20分待っても終わらない...
結局何回やってもダメだったので、「OSを更新したからHomebrewの調子が悪いんかな?」ということでHomebrewのアンインストールをすることに。
そして再インストールをすることになったのですが、今度はHomebrewのインストールで止まる...
もう弾けそうでしたね、逆に。
何度か「usr/local」配下に作られているhomebrewやCellarなどを除去してはインストール、ということを繰り返していましたが結局解決はできず。
そこで試したのが「セーフブート」です。
セーフブートはmacの起動時のオプションでキャッシュクリアなどをして最低限の状態で起動してくれるモード。
セーフブートで起動してからさらに再起動するとキャッシュクリアして綺麗な状態で起動することができるんですね。
早速これを行いまたインストールしたところ、Homebrewもwatchmanも問題なくインストールされました...
おそらくキャッシュに残っているところをインストール時に見に行ってたんですかね??
細かいことはわかりませんが、とりあえずセーフブートからの再起動で正常にHomebrewが正常に戻り、Watchmanもインストールができました。
あとはもうこっちのもんです。
先ほどの「create-react-native-app プロジェクト名」で作ったプロジェクトにcdして「npm start」を打つだけ!
そうすると、「starting packager...」という文言が出て、最終的にはそこにQRコードが表示されます。
このQRコードを読むことで、シミュレーターを表示できるのですがここで必要になってくるのが「expo」というアプリ。
これはiOSでもAndroidでもダウンロードできるアプリなので、個人的にはexpoを使って実機で確認するのが一番いいのかなーとか思ったりしますね。
もちろん「npm run ios」をするとXcodeのシミュレーターが立ち上がったりしますが、結局はexpoに行くので...
ということで、開発環境はexpoを使った方法がおすすめです!
ふう...
本当はコードについてもお話しようと思ったのですが、ちょっと酔いが回ってしまったのでまた今度の機会にさせてもらおうと思います...
今回の内容でとりあえずReactNativeを動かすことはできるのでぜひお試しあれ!
Seleniumでブラウザテストを自動化!Javaでブラウザを動かそう!
今回はブラウザテストについてお話ししようと思います。
以前記事で書いた「診断コンテンツ」がありましたが、結局これはReactを使ってもっとボリュームのあるものを現在開発しています。
ただ、診断コンテンツのように選択肢によって結果が変わるものには「テスト」が必要。
しかし、今回開発しているのは「2つの選択肢がある設問が9個」で選んだ選択肢によって結果が分かれる、というもの。
つまり単純に考えると「2の9乗=512通り」のパターンがあることになります。
「こりゃあえらいこっちゃ…」
512通りを全て確認するのはかなり大変ですよね。
現在完璧に全部をテストできる状態にはなっていないのですが、Seleniumを使ってブラウザテストを初めてやってみたので備忘録として残しておきたいと思います。
Seleniumとはなんぞ???
Seleniumとは、UIテストツール、というかブラウザで表示されている要素を直接触れることなくスクリプトで操作できるツールです。
RubyやPythonなど様々な言語で利用できるものですが今回は昔少しだけ触ったことのあるJavaを使ってみました。
では早速ですが、Seleniumで操作することのできる簡単な例をご紹介したいと思います。
String url = ""; String type = ""; try { url = "https://www.yahoo.co.jp/"; } catch (UnknownHostException e) { e.printStackTrace(); } WebDriver driver = new ChromeDriver(); driver.get(url);
こちらを動かすと、自動的にGoogleChromeで「yahoo」のHPが表示されます。 こちらのコードは簡単ですが、基本となるものなのでしっかり抑えておきましょう。 まず重要になるのは「WebDriver」です。 WebDriverはなんとなくのイメージとしてブラウザに繋げるためのオブジェクトと捉えていただければ大丈夫かと思います。 そしてこのWebDriverという型でブラウザのdrverをnewしてインスタンスを作るわけなのですが、このインスタンス化によってどのブラウザを使うか、ということを選ぶことができます。 今回使用したのは「GoogleChrome」なので「ChromeDriver」をnewしてdriverインスタンスを作っています。 このインスタンス化をすることによってWebDriverがもつメソッドを利用することができるんですね。 上の例で使っているメソッドは「get(URL)」というメソッドで、これは引数のURLを開くメソッドです。 そのため、上の例ではyahooのURLが入っているのでこれを実行するとyahooのHPが表示される、というわけです。 このようなメソッドは他にもあり、WebDriverインスタンスを作ることで表示されている要素を検索して取ってきたり、要素をクリックできるようになったりします 。 さて、今回やりたいことは「512通り」ある選択肢を漏れなくテストしたい、というもの。 テスト内容としては、結果ページで出た「タイプ名」と、条件とした選択肢通りにクリックしてそのタイプになるかを確認したい。 となると、まずは2の9乗のパターンを全部吐き出すような処理を書かなければいけません。 ここで、今回行うテストの想定は - 1か0で判断してどちらの選択肢をクリックするかを決める - 2の9乗なので、「512」になるまで2進数で9桁の文字列を配列で作る というようなことを考えました。 開発している診断コンテンツは「右」か「左」のどっちを押すか、というようなものですので0か1で判断することはもちろん可能です。 では512通りの選択肢を試すためには何が必要か、と考えた時に2進数で512になるまで一つ一つの数字を2進数で表す、という考えに至りました。 先に512 までの2進数を表示するためのメソッドを載せておきます。
public String arrayCreate(int index) { List<String> decimal_array = new ArrayList<>(); // 二進数の配列を作成 for (int i = 0; i < 30; i++) { String decimal = Integer.toString(i, 2); String decimal_fill = String.format("%09d", Integer.parseInt(decimal)); decimal_array.add(decimal_fill); } return decimal_array.get(index); }
こちらはStringで引数に指定されたインデックス番号の文字列(2進数)を返すメソッドとなっています。 やっていることは非常にシンプルで、for文の「i」を1から30まで一つづつ「toString」で2進数化し、その進数を9桁の数字になるようにString.formatで整形して返す、というもの。 そしてテストするメソッドはこちらです。
public static String ClickHandler2(String args) { String url = ""; String type = ""; // IP取得 try { InetAddress address = InetAddress.getLocalHost(); url = "http://" + address.getHostAddress() + ":8888"; } catch (UnknownHostException e) { e.printStackTrace(); } WebDriver driver = new ChromeDriver(); WebDriverWait wait = new WebDriverWait(driver, 20); driver.get(url); WebElement start = driver.findElement(By.className("start-btn")); start.findElement(By.tagName("a")).click(); if (driver.findElements(By.tagName("button")).size() != 0) { System.out.println(args); for (int z = 0; z < 10; z++) { if (driver.findElements(By.tagName("button")).size() != 0) { List<WebElement> el = driver.findElements(By.tagName("button")); WebElement el0 = el.get(0); WebElement el1 = el.get(1); switch (args.charAt(z)) { case '0': el0.click(); break; case '1': el1.click(); break; } } else { System.out.println("結果ページです"); WebElement h1 = driver.findElement(By.tagName("h1")); String src = h1.findElement(By.tagName("img")).getAttribute("src"); type = src.substring(src.length() - 5, src.length() - 4); System.out.println(type); } } } return type.toUpperCase(); }
このメソッドは先ほどのarrayCreateで返された二進数の文字列を引数にして、その文字列が「0か1か」で9問目まで判別し、その判別結果によってボタンをクリックさせる、という内容になっています。 最終的に返されるのはtypeというString型の変数で、こちらが結果ページの「タイプ」です。 そしてテストケースはこちら。
@Test public void test0() { Assert.assertEquals("R", ClickTest2.ClickHandler2(arrayCreate(0))); }
予想されるタイプを第一引数、そして先ほどのメソッドで返されるタイプを第二引数にしています。 現在テストケースはこれしか作成していませんが、なんとなく512まで作れそうな気だけはするような… それぞれのメソッドに関してはまた後日お話しします。 今回は初めてSeleniumを使ってみたら意外といろんなことができるんだなあ...というお話しでした!
イラレの個人的注意点をまとめてみた
さて、しばらくコードの話をしていたので今回はイラレについてお話しようと思います!
私は業務でデザイナーさんから送っていただくデザインを元にコーディングすることが多いのですが、その場合フォトショかイラレかのどちらかをいただきます。
その中でもイラレの方がなんとなーく迷うことがありそうなので備忘録がてら書いていこうとおもいます。
ダイレクト選択ツールで選択しようとしたら背景が持ってかれる...
直感的に使うとなると陥りやすいやつですね。
こちらはかなりシンプルで背景レイヤーにロックをかけるだけで解決できます。
また背景レイヤーだけでなく、選択したくないレイヤーや動かしたくないレイヤーにはあらかじめロックをかけておくといいかもですね。
クリッピングパスがかけられているレイヤーを余白なしで書き出したい!
普通にクリッピングパスがかけられているレイヤーを選択して書き出そうとすると、そのクリッピングがかけられている元のレイヤーのコンテンツは含まれませんが、元のレイヤー分の幅・高さで書き出されてしまうので余白が生まれてしまいます。
その際には、アートボードツールを使うと綺麗に書き出すことができます。
まずダイレクト選択ツールでクリッピングマスクがかけられているレイヤーを選択します。
そしてアートボードツール(mac:shift+O)に切り替え、そのレイヤーをもう一度クリックするとその選択したレイヤーでアートボードが作られます。
アートボードができたらあとは「書き出し」から「スクリーン用に書き出し」で書き出したいアートボードを選択して書き出せばOKです。
簡単な内容でしたが備忘録として残しておきます...
React.jsの環境をnpmで作ろう!APIからデータを取得する方法も実践!
今回は先延ばしにしていたReact.jsを使うための環境構築、そしてAPIからデータを取得して利用する方法についてご紹介していきたいと思います。
いや〜propsの理解についても苦労しましたが、何と言っても環境構築が一番手間取りましたね...
最近ではDockerなどを使って仮想環境を作成することもあるのですが、どうもその辺りが苦手でして(汗
とは言え、React.jsの場合はnpmで「create-react-app」というコマンドがあるので、それを知ってさえいれば苦労はしなさそうですが...
ということで今回はnpmで一からReactを利用できるようにするまで、そしてタスクランナーの設定までご紹介したいと思います!
さて、Reactの環境を作るために必要なものはなんなのでしょう?
純粋にReactのコードを動かすためなら必要なものは以下の二つです。
npm install react npm install react-dom
これはreactとreact-domのパッケージを追加するためのコマンドですね。
しかし、これだけではReactのコードを記述することができてもjsxの記法しておりませんので、前回そして前々回に私が作成したようなrender()の中にHTML
を書くような記法は取ることができず、あくまでjsのネイティブ的な書き方をするしかありません。
でも、どうせなら可読性の高いjsxの記法をしたいですよね???(強制)
ということで、今回初めてjsの依存関係を整理してくれる「browserify」を使ってみました。
gulp.task('browserify', function() { browserify('./src/index.js', { debug: false }) .transform(babelify,{presets: ['es2015', 'react']}) .bundle() .on("error", function (err) { console.log("Error : " + err.message); }) .pipe(source('bundle.js')) .pipe(gulp.dest('./dist')) });
私はタスクランナーとしてGulpを使っているのですが、browserifyのタスク指定は上記の通りです。
最終的にindex.jsというコンポーネントをbrowserifyするのですが、このindex.jsは一般的にいちばん親のコンポーネントであるApp.jsのさらに親のコンポーネント。
つまり関係性を表すとすれば↓のようになりますね。
index.js -App.js -Componet1.js
んー、ちょっと具体例がわかりにくいですかね...
本来であればApp.jsでbrowserifyをかけてもいいのですが、なんとなくスッキリしているのが好きなのでindex.jsというさらにラッパーなjsを作成しているような感じです。
ちょっとわかりづらそうなので一部コードを載せてみたいと思います。
index.js
import React from 'react' import ReactDOM from 'react-dom' import App from './component/App' ReactDOM.render( <App />, document.getElementById('content') );
Componet.js
mport React from 'react' import {render} from 'react-dom' class Question extends React.Component { render(){ if(this.props.count > 0){ return( <div id="questions" className="questions"> <button onClick={this.props.countHandler}>push</button> <p>{this.props.count}</p> {this.props.question.map((data,index)=>{ if(index === this.props.count){ return( <div key={`Q${index+1}`} id={`q${index+1}`} className="inner"> <p key={index}>{data.text}</p> <img key={`imgQ${index+1}`} src={`../img/q0${index+1}.jpg`} /> <div className="question"> <button className={data.question[0].type} onClick={this.props.answerCountHandler}>{data.question[0].text}</button> <button className={data.question[1].type} onClick={this.props.answerCountHandler}>{data.question[1].text}</button> </div> </div> ) } }) } </div> ) } else { return (null); } } } export default Question;
App.js
import React from 'react' import {render} from 'react-dom' import Question from './question' import Start from './start' import Result from './result' class App extends React.Component { constructor(props) { super(props) this.state = { count: 0, questions: [], results: [], countType: [], userAnswers: [], done: false, type: '', hasError: false, isLoading: false, } } //----------関数定義 st----------// componentDidMount() { this.fetchQuestionData('../data/data.json'); this.fetchResultData('../data/result.json'); } fetchQuestionData(url) { this.setState({ isLoading: true }); fetch(url) .then((response) => { if (!response.ok) { throw Error(response.statusText); } this.setState({ isLoading: false }); return response; }) .then((response) => response.json()) .then((data) => this.setState({ questions: data })) .catch(() => this.setState({ hasErrored: true })); } fetchResultData(url) { this.setState({ isLoading: true }); fetch(url) .then((response) => { if (!response.ok) { throw Error(response.statusText); } this.setState({ isLoading: false }); return response; }) .then((response) => response.json()) .then((data) => this.setState({ results: data })) .catch(() => this.setState({ hasErrored: true })); } //----------関数定義 en----------// render() { if (this.state.hasError) { return <p>error</p>; } if (this.state.isLoading) { return <p>loading . . . </p>; } return ( <div className="App"> <Start count = {this.state.count} countHandler = {this.countHandler.bind(this)}/> <Result count = {this.state.count} result = {this.state.results} /> <Question count = {this.state.count} question = {this.state.questions} countHandler = {this.countHandler.bind(this)} answerCountHandler = {this.answerCountHandler.bind(this)} /> </div> ); } } export default App
かなり長くなってしまいましたが関係ないところは一応省きました。
コードの中身はとりあえず追わないでもらって、今みて欲しいところはimportとexportです。
見てもらえればわかると思うのですが、上記の中でindex.js以外は全てそのクラス自体をexportしています。
そしてApp.jsではComponet.jsのクラス「Question」をimportし、index.jsではそのApp.jsをimportしてReactDOMで最終的にimportしてきたApp.jsをrenderしています。
ぶっちゃけindex.jsを作る必要はあまりないのですが、実行クラスを完結にすることでなんとなくスッキリしますよね。
そして最終的にはこのindex.jsをbrowserifyすることで各コンポーネントとの依存関係を解決しています。
いやーbrowserify便利ですね。
さて、Reactの環境を作るのに必要な要点はこのreactのパッケージ、そしてコンポーネントごとに分けるならbrowserifyが必要なのですが、もちろん他にもインストールするべきパッケージは多々あります。
こちらのpackage.jsonをnpm installすればReactの環境は作れると思いますので、ぜひ試してみてください!
{ "name": "npmreact", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "watch": "watchify -t babelify ./app.js -o ./build.js", "start": "browser-sync start --server --files='./*.html, ./*.js'" }, "author": "", "license": "ISC", "dependencies": { "babel-core": "^6.26.3", "browser-sync": "^2.24.5", "browserify": "^16.2.2", "gulp": "^3.9.1", "gulp-autoprefixer": "^5.0.0", "gulp-babel": "^7.0.1", "gulp-sass": "^4.0.1", "gulp-sourcemaps": "^2.6.4", "gulp-uglify": "^3.0.0", "react": "^16.4.1", "react-dom": "^16.4.1", "vinyl-source-stream": "^2.0.0" }, "devDependencies": { "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "babelify": "^8.0.0", "watchify": "^3.11.0" } }
さて、Reactの環境構築についてはこのあたりにして、最後にAPIからデータをとって利用する方法についてご紹介します。
今回作成したのはgithubにあるAPIを叩いて、配列のnameだけをリストにしたものです。
codepen.io
ここで重要なのはやはりfetchですね。
Appクラス~~~ componentDidMount() { this.fetchData('https://api.github.com/users/mismith0227/repos') } fetchData(url) { fetch(url) .then((response) => response.json()) .then((responseData) => { this.setState({ data: responseData, }) }) }
ここではfetchDataというメソッドを定義して、引数にAPIのurlを指定するようにしています。
ComponetDidMount()というのはReactのライフサイクルに関わるメソッドなのですが、これに関してはググってみてください。
さて、肝心のfetchですがデータの取り方や渡し方は普通のjsと同じですのでMDNでfetchを調べてみるといいと思います。
ただ普通とは違うのが最後の「setState()」ですね。
これで空配列のstate「data」にAPI で取得したものをセットしています。
これによってstateとしてAPIのデータを利用できるので、あとは前回と同じです。(map関数に関しては次の機会でお話したいと思います...)
このようにして、APIで叩いた結果をReactで利用できるようになるんですね。
実際に実行できるようになるまでは時間が少しかかってしまいましたが、コード自体はシンプルなのでぜひ上記コードにあるgitのAPIで試してみてください!
さて、今回はReactの環境構築とAPIを叩いてデータを利用する方法を見ていきました。
環境構築を一から行うのはやや骨が折れると思いますが、冒頭でもお話したようにcreate-react-appという便利なコマンドがあるようなので、今ならそこまで時間がかからないのかもしれませんね。
またAPIも簡単に利用できるのでReactでできることの幅も一気に広がると思います。
参考になるかはわかりませんが、私が作成したものを煮るなり焼くなりして動きを掴んでもらえればと思います...
では次回は「Reactでの注意点やmap関数について」をお送りしよう(変わるかも...)と思いますので次回もよろしくお願いいたします!
個人的難敵「props」とは?stateとの関連も含めてオレオレ解説
さて前回はReactの概要的なところから最終的にはstateを使ったカウントアッププログラムまでを説明しました。
前回のような単純なプログラムであればstateだけでも確かにいけるのですが、それではまだReactの恩恵に預かっているとは言えないよう。
今回ご紹介するのは主に「props」について!
私はこのpropsというものがよくわからなすぎて悶絶していたこともあり、Reactの中で一番の難敵?と思っています...
「stateとpropsとは?」という記事がよくありますが、前回も言ったように学び始める際にはこの二つは「分離して考えた方が良さそう」というのが個人的な見解です。
前回はstateを使ってカウントアッププログラムを作成してみましたので、今回もわかりやすいようにこのプログラムを踏襲してpropsについてご紹介したいと思います。
codepen.io
今回作成したものは前回作成したカウントアッププログラムと実行結果を同じもの。
そして前回作成したものはこちらです。↓
codepen.io
こちらではCountクラスのstate「count」をそのままCountクラスのrenderメソッドで描画しています。
しかし、今回作成したものでCountクラスのstate「count」を描画しているクラスはCountではなく「CountNumber」というクラス。
(余談ですがReactではクラスを定義する際に最初の文字が大文字でないと怒られるので注意です...パスカルケース?って言うようですよ...
そして今回作成したものと前回作成したもので違う点がクラス以外にもう一つ。
それが「Count」クラスの中にある「constructor」の「props」。
ここでようやくpropsが出てきましたね〜
propsはproperties(プロパティ)の意味のようで、そのクラスがもつプロパティと考えて良さそう。
しかしこれとstateの違いが最初はわからなかった...(今も曖昧ですが)
ですが先ほども言ったようにstateとpropsを一度分離してみるとわかりやすかったです!
前回作成したものはstateだけで動いてしますが、今回作成したものはpropsも使って動いています。
この二つでの違いはズバリ「新しいクラスに値を渡すかどうか」でしょう。
今回はCountクラスで定義したcountというstateをCountNumberというクラスに渡しています。
この時に重要なのがpropsでpropsを使うことで、自身のもつstateを子に渡すことができます。
そしてpropsを利用してstateを渡すお作法がこちら。
constructor(props) { super(props) this.state = { count: 0 }
前回のものをみるとわかりますが、constructor( )とprops( )の引数に(props)が与えられています。
これは正直わからないのでpropsを使って値を渡すために必要なお作法だと覚えておきましょう。
これを使うことで、子のクラスに自身のstateを渡すことができるのですが、渡し方と受け取り方にもあるお作法が。
渡し方のお作法
<CountNumber count = {this.state.count} />
受け取り方のお作法
<p> {this.props.count} </p>
こちらが渡し方と受け取り方のお作法になります。
私がこのようなクラス作ってプロパティ作ってクラスメソッドを...というような言語に慣れていなかったため困惑したのだと思いますが、よくよく考えるとstateとpropsの違いは上記のお作法で完結しているのではないでしょうか?
自身のクラスの状態を表すプロパティであるstateは「this.state」で参照することができるので自クラスのメソッドであるrenderで渡すには自身(this)のstateを参照し、適当な変数に入れて子クラス(他のコンポーネント)に値を渡すことができるわけですね。
少し混乱すると思いますが、このように複数のコンポーネントを管理する場合はまずメインのコンポーネントを作成した後に他のコンポーネントの骨組みを作ってしまった方がわかりやすい気がします。
今回の場合はただカウントアップしていく「数字」のみを表示するコンポーネント「CountNumber」を作って、その後にメインコンポーネントである「 Count」でCount自身のstateをCountNumberに渡すようにしています。
そして前回抜けていた関数を実行する場合にもあるお作法があります。
<button onClick={this.countUp.bind(this)}>push!</button>
Reactではこのように現在のHTMLではあまりよしとされていない「onclick」を使ってイベントを設定することができます。
ここで関数を設定するお作法は「{this.countUp.bind(this}」というもの。
CountクラスではクラスメソッドとしてCountUpというものを定義していますが、これをrenderメソッド内で参照するにはstateと同じようにthisが必須。
しかし、ここで重要なのは「bind」です。
動かしてみるとわかりますが、このbindがないとこのプログラムは動きません。
これもよくわかっていないのですが、bindとはそもそもbind(オブジェクト)のようにあるオブジェクトに関数を紐づけて新しい関数を作成するというもの。
thisについてはまだまだ勉強中ですので詳しいことはお話できませんが、ここで言えば自身のクラスにこのクラスメソッドを紐づけている、ということで良さそうです。
このbindを与えることで関数が実行できるようになるのでこれも覚えておきましょう。
そして関数を渡す場合のお作法もほぼstateを渡すような場合と同じです。
渡し方のお作法〜関数編〜
<CountNumber countUp = {this.countUp.bind(this)} />
受け取り方のお作法〜関数編〜
<button onClick={this.props.countUp} >push! </button>
こちらもpropsを通じて受け渡しをすることができるんですね。
この例でもわかるように、とにかくpropsはstateやメソッドなどクラスで定義されているものを受け渡しするためのもの、と考えていいです。
stateは自身の状態を定義するだけのものなのでここがpropsと違いますね。
さて、propsとstateの違い、また関数の実行の仕方についてオレオレ解説していきましたがいかがでしたでしょうか?
Reactを触っていく中でも感じましたがやはり「触ってみることが大事」ということをひしひしと感じましたね。
一通りReactの概要やお作法に関しては解説したつもりなので、次回はReactをnpmで環境構築をする場合、少し発展?してAPIからデータを取得して利用する、といったことについてお話していきたいと思います!
「初心者と学ぶReact.js!」入門チックなことを書いてみよう
今回は何かと話題のFacebook謹製jsライブラリ「React.js」について学習した記録を書き綴ろうと思います。
Angular、Vue、Reactの御三家みたいなところはありますが、なんとなく名前がかっこいいのとFacebook製というところに惹かれ一週間前からちびちび学習してみた、というのが学習のきっかけですね〜
ということで学習してみたはいいものの、これまた意外と難しい...
「チュートリアルが優しい!」ということでも有名なようですが、自分の理解力のなさが露呈してしまいましたねえ... (意外と同じようなかた多いのではないだろうか(希望)
さて、そんなことはさておきましてなんやかんやでReactで一通りの使い方や考え方を自分なりに掴んだつもりでおりますので今回書いてみようと思った始末でございます。
では早速、Reactとはどのような仕組みなのかをオレオレ解説でいってみよーと思います。
Reactの仕組みをオレオレ解説
Reactとは先ほどもいったように、Facebook謹製のjsライブラリです。
よく言われているのが「MVW」のV、つまりView部分を担っているのがReact。
そしてReactの考え方で重要なのは「Component(コンポーネント)」です。
このComponentは直訳で「構成要素・成分」などの意味がありますが、まさに役割としては意味の通りで「構成要素」と考えてもらっていいと思います。
まあjsを使用する中で「コンポーネント化」というのは聞き馴染みのある方も多いのではないでしょうか?
処理ごとにjsを分けて最終的に一つのjsにまとめて読み込む、というアレですね。
これはscssやphpのテンプレート化でも使われている考え方ですし、これからは「コンポーネント化することが主流となる」とも言われています。
少し脱線しましたが、要するにコンポーネントは構成要素で部品です。
このコンポーネントを最終的に組み合わせて一つのアプリケーションを作ることがReactの考え方で、それぞれをコンポーネントとして分けることでそれぞれの保守性を高めている、と考えて大丈夫そう。
少し文字が多くなってしまったので、ここで例をみてみたいと思います。
こちらは簡単なサンプルです。
こちらのサンプルはcodepenで作っていますが、ちょっと設定に戸惑ったのでメモ。
1.settingsからjsを「Babel」にする。
2.「Add External Scripts/Pens」からcdnのURLを読み込むか、「Quick-add」からReactを選ぶ
基本設定はこれで終わりますし、あとはコードを書くだけなので、よかったら試してみてください。
一番時間がかかったReactをnpmで使う場合も今度の機会に...
さて今回のサンプルですが、二つのクラス「Hello」と「World」を作り、それを「HelloWorld」というクラスでまとめて、最後にHelloWorldクラスをidがrootの場所に配置する、というもの。
Reactの記法はバージョンによってコロコロ変わっているようですが最新のドキュメントではこちらの記法が推奨されているよう。
クラスを作る方法は、「class クラス名前 extends React.Component」でいけます。
そしてこのクラスはほぼコンポーネントと考えて良さそう。
厳密に言うと違うようですがそんな感じの理解でいいでしょう(適当)
そしてクラスにはある重要なメソッドが含まれています。
それが「render」というメソッド。
このrenderについては正直あまり考えなくていいと思うのですが、どうやらHTML要素を生成するためのもののようです。
このrenderを使わないとどうにもなりませんし、renderで返すものが一つもないとえらーになります。
つまりコンポーネントを作成するにはrenderが必要で、renderで返すものがないとComponentは作成できない、ということですね。
さて、ここまではなんとなーく理解ができるような気がします。
しかし私を悩ませたよくわからないもの二つが↓から登場するのです...
こちらはボタンを押すとカウントが上がるというシンプルなアプリケーションです。
基礎を学ぶには一番いいのかな?と個人的に思いましたね。
そして私がよくわからなかったものは上記に出てくる「state」と「props」です。
正直、上記の例ではstateだけで動かせてしまうので最初のうちはpropsについて深く考えない方が得策な気がしましたね。
さて、まず攻略したいがのこのstateというもので、これは直訳すれば「状態」という意味を持ちます。
今回で言えばCountクラスの中の「state:状態」としてcountというプロパティを持っている、と言えます。
そしてReactの特徴なのが、このstateによって描画(render)されるものが変わっていくということ!
拙い例ではありますが、カウントがどんどん上がっていくのがいい例ですね。
ではこのstateをどのようにして更新していくのか?
それはsetStateというメソッドを使うことで実現することができます。
実はReactではstateを「this.state.count += 1」のように更新することはできません。
その代わりにsetStateというメソッドを使ってしっかりstateの値を変えることを明記する必要があるんですね。
setStateの使い方は上記の通りで「setState( { state名:変数や値 } )」とするのが作法です。
今回の例では最初に変数countを定義し、その変数を+1したのちにsetStateするという流れになっています。
この考え方は重要なので覚えておくといいですよ!きっと!!笑
そして今回定義している関数「countUp」なのですが普通のjsとは少し書き方が違いますよね。
これも作法なのでとりあえずは何も考えないでこのように書いてみてください。
さてここまでで、「class」「render」「state」について知ることができました。
次はいよいよpropsなのですが、propsはちょっと長くなるかもなのでとりあえず今日なこの辺で終わりにしようと思います...
初心者で拙い解説ではありますが、少しでもお役に立てればよいなあ...