もやぶろ

moyashidaisukeのブログだからもやぶろ。フリーランスのエンジニアのダイスケです。QOLあげて色々楽しくチャレンジして良く生きたい。プログラム関連とかギター関連とか旅行関連とか色々。

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にしました。

reactjs.org

コード

これです。 github.com

オフィシャルの完成品はこちら。

https://codepen.io/gaearon/pen/gWWZgR?editors=0010codepen.io

メモ

環境周り

環境はcodePenでブラウザ上でやるのと、ローカル環境でやるのが選択できるのですが、ローカルにしました。どちらにしろ必要なので。

nodeを実行しろとの事ですが、ローカル環境にあまり色々入れてなくないのでdockerで環境構築してます。

参考 qiita.com

mherman.org

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というのがあるらしいですね。

www.wantedly.com

また、boolやinteger(number)の値はコピーとかしなくていいのかな、と思ったらjavascriptではスカラー値はそもそもimmutableなんですね。

sbfl.net

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個あるのでやってみます