react.jsのチュートリアル(Tutorial: Intro to React)をやった その1
やってみました。
ちょっとしたwebアプリ作ってみようかなと思っているのですが、
- スマホアプリにもするかもしれない
- reactNativeにするかも?
というわけで、reactでweb版をとりあえず作ってみようかと。その準備としてチュートリアルやってみました。
ちなみに、vue.jsは業務で使ってた事があります(Nuxt.js好きです)。 react.js VS vue.js VS angular.js は良く語られますが、実際に使ってみて判断してみようかと思い、敢えて使ったこと無いreact.jsにしました。
コード
これです。 github.com
オフィシャルの完成品はこちら。
https://codepen.io/gaearon/pen/gWWZgR?editors=0010codepen.io
メモ
環境周り
環境はcodePenでブラウザ上でやるのと、ローカル環境でやるのが選択できるのですが、ローカルにしました。どちらにしろ必要なので。
nodeを実行しろとの事ですが、ローカル環境にあまり色々入れてなくないのでdockerで環境構築してます。
参考 qiita.com
nodeのバージョン調整と、
FROM "node:8.12-alpine"
docker execして作業しやすいように
tty: true
を追加しています。
エディタはPHPStormでいい感じに補完効いたので、PHPStormにしてます。(多分JetBrainの他の製品でもいける)
ハマりポイント
devツールインストールしてもtabが出なかったのですが、ブラウザ再起動したりしてたら出るようになりました。よくわかりません。
その他メモ
immutable推奨
immutable推奨なので、いちいちsliceしたり
var player = {score: 1, name: 'Jeff'}; var newPlayer = Object.assign({}, player, {score: 2}); // Now player is unchanged, but newPlayer is {score: 2, name: 'Jeff'} // Or if you are using object spread syntax proposal, you can write: // var newPlayer = {...player, score: 2};
みたいに書かないといけないのが疲れるなぁ、、、
と思って調べてたら、やはり考えることはみんな同じらしく、immutable.jsというのがあるらしいですね。
また、boolやinteger(number)の値はコピーとかしなくていいのかな、と思ったらjavascriptではスカラー値はそもそもimmutableなんですね。
XOの判定が冗長なのをどうにかしたい
最終型でも
squares[i] = this.state.xIsNext ? 'X' : 'O';
status = 'Next player: ' + (this.state.xIsNext ? 'X': 'O');
という冗長な処理があります。
MVCっぽく考えると、this.stateにfunctionをもたせたくなっちゃうけど、react的にはGameクラス内にヘルパー関数作る方が良いのかなぁ、、、
お作法がちょっとわからないです。
functionを先に定義したい
チュートリアルの順番として、
hoge functionを呼ぶ処理を書く→hoge functionを実装する
という流れが何回か出てきます。
この順番だと、
- 一時的に動かない状態が発生する
- hogeが補完効かないのでtypoの元になる
というのがあるので、
- 先にhoge functionを定義
- または、呼び出し元でhoge functionに該当する処理をとりあえず書いてからリファクタして別function にする
という順番にして欲しいな、と思いました。
変数名がイケてないところがある
step周り
○☓ゲームの何手目か、を表す値があるのですが、統一されてなくて混乱します。
const moves = history.map((step, move) => { // currentValue, index const desc = move ? 'Go to move #' + move :'Go to game start'; return ( <li key={move}> <button onClick={() => this.jumpTo(move)}>{desc}</button> </li> ); });
jumpTo(step) { this.setState({ stepNumber: step, xIsNext: (step %2 ) === 0, }) }
jumpToあたりの「stepNumber」と「step」はまあぎりぎり許容できるかな、と思うのですが、
history.map((step, move)
は、う〜ん、、
これ、stepにはその時の盤の状態、moveには何手目かが入っています。 stepが、stepNumberと全然違う値なのに同じような名前になってて混乱します。 もっと言うと、historyという名前も何のhistoryなのか(盤の状態なのか、N手目を打った座標を表すのか)が読み取れないです。
なので、
history -> boardStateHistory
boardStateHistory.map((boardState, stepNumber)
にするとスッキリするのでは。
calculateWinner
function calculateWinner(squares) { const lines = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6], ] for (let i = 0; i < lines.length; i++) { const [a, b, c] = lines[i]; if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { return squares[a]; } } return null;
これなのですが、calculateなのに、勝った人(○ or ☓)or null が返ってくるんですね。 勝った人を返すなら、getWinner とかが良いんじゃないかなぁ、、、
ファイルとclassの単位はどうするのが良い?
index.jsにclassを3つ書いてるのですが、1:1 にするのか、チュートリアルのように良い塩梅でまとめるのか、どちらが良いんですかねぇ、、、
class毎にファイルを分けた方が、後で探す時に迷子にならないように思えますが、、、
JSXが慣れない
javascriptの中に素のhtmlが普通に出てくるのが異次元体験過ぎてびっくりしました。
この点については、今の所vue.jsの方が良いかなぁ、、、という感想です。cssもセットで管理できるし。(reactはcssどう扱うのかまだ良くわかってません)
たくさん書いてれば逆にこれが気持ちよくなって来る人もいるようなので、とりあえず目をつぶっておきます。
この後
追加の宿題みたいなのが6個あるのでやってみます