地方エンジニアの日記

山口県でエンジニアをしています。元々都会の方で1年ほどWEB系のエンジニアをしていました。都会と比べると、学びの場を自分から作っていかないとなかなか難しいと感じています。

今度こそローカル環境で実行させるReact

ReactをJSXを用いてコードを作成するまでは良かったのですが、「ここからどうやって実行するの?」とつまりました。 以前の記事( Reactの環境を構築する (エラーにハマって未解決) - 地方エンジニアの日記 )は、詰まってからもがいたのですが、力つきました。笑

問題は、.jsxを.jsに変換した後にも、node_modulesからimportしている部分があることです。

// index.js
import ReactDOM from 'react-dom';

このコードの部分でエラーがおきます。では、どうすればhtmlで実行できるのか、そこが今回の記事の主題です。

対策その1: node_modules以下のファイルを直指定して読み込む

<script src="node_modules/react/dist/react.min.js"></script>
<script src="node_modules/react-dom/dist/react-dom.min.js"></script>

上記のように読み込めば、import自体必要なくなります。

対策その2: webpackを利用する

そもそもなぜこの問題が発生しているのか、それを知るには、モジュールという概念を知る必要があります。モジュールとは、1ファイル(一つのコードのまとまり)のことです。1ファイルは独立しているので、他のファイルに影響を与えることはありません。スコープの概念ですね。

外部のファイルを利用したい時には、「外部のファイルを使います!」と宣言する必要があります。それが、最初のコードで記述した、import文です。

これにより、外部との衝突などを考える必要性が大きく減りましたが、各ブラウザがこのモジュールに対応しているわけではありません。なので、モジュールを利用しているものを、モジュールを利用していないものに変換してあげる必要があります。そう、webpackの出番です。

webpackの基本的な役割は、ファイルに書かれたimport文をもとにそれぞれのファイルを束ねること(つなぎ合わせる)です。束ねることで、import文なしで、コードが実行できるようになります。(よくbundle.jsというファイル名を見かけませんか?bundleには束ねる、括るという意味があります。)

大きな流れは以下のような感じです。

複数のjsxファイル => (babel: JSXからJSにトランスパイル) => 複数のjsファイル => (webpack: モジュール解決) => bundle.js

babelとwebpackがそれぞれの役割を果たすことにより、jsxをjsに変換し、モジュールに分割していたものを1ファイルにまとめることができます。

手順を覚えていないので、私のgithubリポジトリのpackage.jsonを参考にしていただければと思います。

github.com


ブログ継続日数 17日目 諸事情により前回の投稿から2週間近く空いてしまった。。。またちょっと空くかもしれない。

Reactの環境を構築する (エラーにハマって未解決)

Reactのチュートリアルが終わり、続いてドキュメントのMAIN CONCEPTを一通り写経しながら進めていこうと考えました。

ただそのための環境構築について詳しく書かれていないというのは語弊があるのですが、ローカルでJSXをトランスパイルして実行する説明が少なく詰まってしまいました。 今日2時間くらいの成果がこれなので、仕方なく記録としてここに書きます。(明日はうまく動くようにしたい。というかまず何が問題かをはっきりさせる。)

うまく動かなかった手順

Add React to a Website – React

上記のリンクの通りにやってみたのですが、なぜか動きませんでした。.jsxから.jsへのトランスパイルらしきものはできていたのですが、react-domなどのインポートがなぜかうまくいきませんでした。(scriptで外部から読み込めば動いたので、それでOKといえばそうなのですが、JSXをトランスパイルするだけで完結させたかったので、今回はうまく動かなかったという表現をしています。)

# node.jsが入っていることを確認
node -v

mkdir target-directory
cd target-directory

#  package.jsonを作成
npm init -y

#  babel-cliとbabel-preset-react-appをインストール
npm install babel-cli@6 babel-preset-react-app@3

mkdir src

npx babel --watch src --out-dir . --presets react-app/prod 

上記の工程により、src以下の.jsxファイルの変更がindex.jsにトランスパイルされるようになります。

import reactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);

実際に上記のコードを書き、トランスパイルされました。 しかしトランスパイルされたindex.jsをindex.htmlでtype="module"として読み込んでも、

Uncaught TypeError: Failed to resolve module specifier "react-dom". Relative references must start with either "/", "./", or "../".

react-domなんてそんなモジュール見つけられへんかったで。みたいな意味だと思うのですが。(VScodeではコード辿れるんですけどね...。何か書き方が悪かったのでしょうか。)

まとめ・感想

できぬ。。。


ブログ継続日数 16日目

Reactで配列操作をするとエラーが... Warning: Each child in a list should have a unique "key" prop.

Reactチュートリアルも、基本部分は最後までやりきり、ついでだからと発展部分もやってやろうじゃないかと、挑戦しました。

挑戦したのですが、途中で以下のエラーが発生。

index.js:1 Warning: Each child in a list should have a unique "key" prop.

Check the render method of Board. See https://fb.me/react-warning-keys for more information.

listの要素は 一意のkeyを持ちなさいということです。

最初はでていなかったのに...

このエラーチュートリアルの発展編前まではついていませんでした。

問題が発生したのはBoardクラスのrenderメソッド内のrenderSquareメソッドなのですが、コードは以下のようなものでした。

クラス全部だと長いので、一部必要な部分だけ抜粋。全てBoardクラス内のコードです。

renderSquare(i) {
    return <Square
      value={this.props.squares[i]}
      onClick={() => this.props.onClick(i)} />
  }


render() {
    return (
      <div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }

上記のコードの時にはエラーが出ていませんでした。

このコードのrenderSquare部分をfor文を用いて表現した際にエラーは発生しました。

以下がエラー発生時のコード。

render() {
    let squares = [];

    for (let i = 0; i < 3; i++) {
      let row = [];

      for (let j = 0; j < 3; j++) {
        const num = i * 3 + j;
        row.push(this.renderSquare(num));
      }
      squares.push(<div className="board-row">{row}</div>);
    };

    return (
      <div>
        {squares}
      </div>
    );
  }

似たような処理をforを用いてコンパクトにしたのです。

何が問題だったのか

Reactは配列に対して、一意であるkeyという値によって中身に変化がないかを監視しています。

エラー発生前のコードでは配列構造を用いずに一つ一つ個別にコードにしていました。

一方、エラー発生時のコードでは、renderSquareメソッドの結果をrowという配列に追加し、さらにrowをsquaresに追加しています。

つまり、二つの配列が使われていることになります。この両方に対して一意のkeyを渡してあげる必要があります。(おそらく配列内で一意であればよい)

修正後のコード

renderSquare(i) {
    return <Square
      key={i} 
      value={this.props.squares[i]}
      onClick={() => this.props.onClick(i)} />
  }


render() {
    let squares = [];

    for (let i = 0; i < 3; i++) {
      let row = [];

      for (let j = 0; j < 3; j++) {
        const num = i * 3 + j;
        row.push(this.renderSquare(num));
      }
      squares.push(<div key={i} className="board-row">{row}</div>);
    };

    return (
      <div>
        {squares}
      </div>
    );
  }

両方に対して、keyを設定してあげることで対応できました。

まとめ・感想

放っておいても動作するにはするエラーではありますが、直せるとわかっていながら放っておくのは嫌だったので、なんとか解決できてよかったです。

参考

こちらの記事ではエラー文で list ではなく arrayと表示されていましたが、エラー文が変わったのでしょうか。list と arrayが違うもののような気がするので、このあたりについてもまた調べてみようかな。


ブログ継続日数 15日目

React チュートリアルで学んだこと

JavaScriptの入門を終える前に、Reactの入門が終わってしまいました。笑

React チュートリアルというのは、Facebookが公開しているマルバツゲームを作成するチュートリアルです。

細かいところまで解説がしっかりしているので、つまづくことはありません。加えて、大事なポイントを強調してくれるので、どこに意識を向ければいいのかもわかりやすいです。

(もしかすると、最新のReactの書き方とは異なる可能性はなくはないですが、公式のチュートリアルのでそこまで大きく解離していることはないと思います。)

今回はそこで学んだポイントについて書いていきます。

Reactとは

Reactは、宣言的で、効率的で、柔軟性を持ったJavaScriptライブラリです。

このライブラリは、小さく単純な独立したコンポーネントを組み合わせて、複雑なUIを作るためのものです。

コンポーネント とは

コンポーネントは、Reactを利用する上で必須の概念です。日本語でいうと、部品、という意味になります。

小さな機能を持った部品を組み合わせることで、複雑なものでも作成することができます。

コンポーネントはprops(propertiesの略)というパラメーターを受け取り、renderメソッドを通して画面に表示する内容を返します。JSXという記法を利用することで、コードとしてみやすい表現ができます。

propsだけでなく、stateと呼ばれるコンポーネントの状態管理のための機能もあります。

状態管理について

Reactでは、コンポーネントに状態を持たせることができます。

例えば、ある図を表示・非表示できるボタンコンポーネントを想定してみます。

ボタンコンポーネントは、表示中か、非表示中かの状態をどこかで持っている必要があります。stateとして持つことも可能ですし、propsを利用して、外部から状態を都度渡すことも可能です。

状態管理はどこかで一括管理するのが基本です。現在は、状態管理のためのフローみたいな物があるようですが、まだあまり詳しくありません。(redux? react hooks?)

一括管理が基本なので、ボタンを持つページを構成するコンポーネントがボタンの状態を管理して、ボタンコンポーネント に状態をpropsを通して渡すという形になります。(複雑になればなるほど、状態管理を司るコンポーネントと状態管理によって表示が変わるコンポーネントとの距離が遠くなってしまう可能性はありますが、これはどうすればよいのでしょうか。このためのredux???なのか...)

コンポーネントの種類

クラスコンポーネントと関数コンポーネントがあります。基本は関数コンポーネントの書き方でよいのだと思います。

// クラスコンポーネント
class Sample extends React.Component {
    return (
        <button className="testButton" onClick={props.changeText}>
            {props.text}
        </button>
    )
}
// 関数コンポーネント
function Sample(props) {
    return (
        <button className="testButton" onClick={props.changeText}>
            {props.text}
        </button>
    )
}

アロー関数

アロー関数は以前のブログでも書きましたが、チュートリアルではとても頻繁に使いました。

やはり束縛する必要がなくなるという点から非常に便利ですね。

state管理について

state管理についてですが、Reactではstateをそのまま書き換えるのではなく、複製を作成して、複製の一部を変更し、それをstateに反映するという流れになっています。

このようにする理由には、

  • 以前のデータに戻すのが楽
  • データの変更点が検出しやすい
  • Reactが再レンダリングのタイミングをキャッチできる(おそらく再レンダリングが必要かを変更前後のデータを比較して検出できるということだと)

上記のような理由があります。

まとめ・感想

今回は詳細に中身について触れた訳ではありませんが、Reactについての理解が深まった要因思います。(これまでなんとなくQiitaを読んだりしていたのですが、しっかり1から作成したのは初めてでした。)

参考


ブログ継続日数 14日目

ほぼって頭につけると続けるのが楽になった件

趣味でも勉強でもなんでも続けているから、その成果が見えてくるのがほとんどです。 趣味であればなんの努力もせずに続けることは難しくないですが、勉強は人によっては、公卿になることもあります。私自身、勉強の内容によってはやる気が出ずに、やらないといけないはずなので手が動かない、ということがよくあります。

あまり気が進まない、けどやらないといけないとき習慣化できていれば気持ちの抵抗なく、行動に写すことがたやすくなります。

ここで、その習慣化とかいうやつにどうやってするんだ?という問題が浮上してくるのです。

今回は、私がそういうあまり気乗りしないものでも習慣化することに成功した方法を紹介いたします。

(今回のべている習慣という言葉は、厳密な意味とは少し違っているかもしれません。というのも、やらない日があっても全く問題ないからです。その前提があることに注意して、お読みください。)

習慣=毎日やらないといけない

あることを習慣にしようとすると、「毎日やろう」と意気込んで、最初の数日で終わるということがありませんか?これが習慣化の罠だと私は思っています。

習慣化に必要なのは、やる気ではなく、ただただ続けられるタスクです。 続けられるようにするために、タスクをできる限り小さくするというのは、とてもよく知られた方法だと思います。

例えば、ダイエットのために運動を毎日すると決めた時、「1日5キロ走る!」などというこれまで運動していなかった人にはほとんど続けるのが困難な目標を立てるよりも、「1日腹筋5回+αその日の気分)」というとりあえず腹筋5回できればいい、という風にする方法です。

これは非常に強力です。しかし、やり忘れることが1度起きてしまうと、「もういっかな」と思ってしまうのが、私のようなズボラな人間なのです。

習慣=毎日じゃなくても続いていればいい

このようなズボラな人のために、「習慣」ではなく、「ほぼ」習慣という思想?を紹介したいと思います。

もともと習慣というものは、毎日やる必要はないのですが、なぜか多くの人があることを習慣化しようとすると、「毎日」という前提がついてしまっています。その前提を「ほぼ」という言葉をつけることで、毎日でなくてもいいと意識的に感じるのが「ほぼ習慣」という言葉です。

これだけでものすごく効果がある

えっ、それだけ!???

そう思うことでしょうが、それだけなんです。でもなぜか続けやすくなります。 これは私の推察ですが、人間とくに日本人というのは学校教育の影響なのか、目標に対して非常に責任感を感じやすくなっているように思います。そして、その目標に失敗した時に、大きな自己嫌悪を感じやすいのではないかと思うのです。そして、続ける気持ちが折れてしまう。。。

こういう仮説のもと習慣化について考えると、とりうる方法は2つあるのではないでしょうか。

  1. 目標失敗時の対応を変える
  2. 目標をとにかく簡単にする(できるちょっと上を目指す)

失敗した時に、自分を責めるのではなく、なぜできなかったのかを考えるように変えていく。これはとても大切です。(正直、今回のほぼ習慣の考え方以上に大切です。 ) 私の身近にもとにかく自分を責めて、心理的にも物理的にも自分を傷つけて、何も解決しないくて、それを繰り返していた人がいます。本当に大切な人なので、見ていて苦しかったです。(今は少しずつ、問題解決的な思考も持てるようになってきました!)

二つ目の、目標をとにかく簡単にすることも大切です。「目標を立ててください」そういわれた時、なぜか壮大な、できるだけ大きくてすごい目標にしないといけないと考えがちではないでしょうか。それ自体は問題ではないと思うのですが、目標を立てる時ってたいてい気分が高揚している時なんです。すごいやる気、熱意に満ち溢れていて、なんでもできそうな気分につつまれていたりして。

こんな時に立てた目標を、気分が落ちた時に遂行できるのか?まぁ9割がたできないんじゃないでしょうか。

私は、気分の浮き沈みがとても穏やかな方だと思います。気分が高揚している時も、落ち込んでいる時も見た目に大きな変化はでません。(心の中でしんどい。。うぐ。。ってなってはいますが。)

でも、気分が落ち込んでいる時は何もやりたくないと思います。それこそ好きな趣味なんかも今はいやだ、そう思うことがあります。日課!?そんなんやってらんねぇ。って思います。(こんな時にでもできる人もいるんだと思うんです。でも自分にはできない。そこを頑張ってできるようになろうとも思わないです。)

だから目標を簡単にすることが大切なんです。いつでもできる、落ち込んでいる時でさえ、「これくらいならできる」と思える目標にしてあげることが。そして、それでもできない日があるので、「ほぼ」をつけてカバーしてあげるのです。

本当に続くようになります!! これを試して1年ほどになりますが、今まで続けられなくて、自分はダメなやつだと思っていたんですが、これまでの目標の立て方が自分にあっていなかったのだなと思いました。

ほぼ日課

例えば、どんな日課をしているのかについて少し書いていきます。 以下の画像が、私がパソコンでほぼ日課にしているものです。

ほぼ日課の画像
ほぼ日課(ブックマーク)

仕事柄、からなず毎日PCでchromeを開くので、 - 投資系の情報整理(米10年金利の確認、yahoo financeをちょっと見る、S&P500のマップを見る) - Feedlyに溜まっている記事を消化する - Qiitaの新しい記事で気になるものを読む - その日に書くためのはてブを開いておく(書き忘れることもあります。) - その他学習(直近は、DBスペシャリストとReact Tutorialの学習です。) (ほぼ日課に入っているフォルダは、今は量的に大変だけど、DBスペシャリストやReactの学習が終われば続いて学びたいことのサイトが入っています。)

上記のようなセットをほぼ毎日行っています。PC版Chromeの良い点は、ブックマークフォルダを新しいウィンドウで開けることです。朝に新しいウィンドウで開いて朝の間に全てを終える or その日が終わるまでにすべてこなす(タブを閉じる作業が少し快感になります)ということができるのです。

もし運動を習慣にしたい人がいれば、このフォルダに運動系の短いYoutubeのリンクを入れておけば、面倒な運動開始までの流れを、開いて再生ボタンを押すという簡単な作業に持ち込むことだできます。


この記事と関係ない内容ですが、タイトルに継続日数を書くのは、あまり気持ちのいいものではなかったので、記事の末尾に書くようにしました。なくすことも考えましたが、主にアウトプットを継続的に行うことが目的なので、日数情報は自分の目で見える形として残したいんですよね。

ブログ継続日数 13日目

#012 アロー関数についてちょっと復習してみた

ES6で追加されたアロー関数ですが、一体何者なんだ?という思いがこれまで拭えませんでした。

というのも、だからなんなのだろう、という思いが少なからずあったためです。

短く書けるのは嬉しいけれど、それにしては取り上げられすぎていないだろうか?そんな思いがありましたので、他にアロー関数ができた理由がないか調べてみました。

目次

アロー関数とは

アロー関数とは、これまでの関数式の書き方をより短くした式です。

var numbers = [1,2,3,4,5,6,7,8,9,10];


// これまでの関数式
var square_numbers =numbers.map(function(element) {
  return element.length;
});

// アロー関数式
var square_numbers =numbers.map((element) => element.length);

メリット1 短くかける

アロー関数のメリットの1つに、短くかけること、読みやすいことが挙げられます。(短いことが必ずしも読みやすいことに繋がるわけではありませんが、アロー関数に限っては、省略される部分が決まっているので、大抵読みやすくなると思います。)

メリット2 thisを束縛しない

短くかけること以外にも、アロー関数には特徴があります。それがthisを束縛しないということです。束縛とは一体どういうことなのか、なかなか理解に苦しむ言葉ではありますが、自分なりに解釈してみました。

束縛とは

束縛という言葉が非常にわかりにくいですが、これは 「関数自身が持つ値を定義するか」という解釈でいいのではないでしょうか。

関数定義時に、アロー関数ではthisという値を定義しない、と言い換えることができます。定義しないため、関数より外のスコープにthisを探しにいきます。

実際、MDNでは以下のような説明があります。

アロー関数自身は this を持ちません。レキシカルスコープの this 値を使います。つまり、アロー関数内の this 値は通常の変数検索ルールに従います。このためスコープに this 値がない場合、その一つ外側のスコープで this 値を探します。

thisはアロー関数より外のスコープにあるものが参照されるようになるわけですね。 これにより、クラス変数などを関数内で利用しやすくなるわけですね。

Reactでもアロー関数を使わない時、やっかいな問題が起きていましたね。(これまで理解できていませんでしたが、ようやくわかりました!!)

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = { msg: "Click!"};
    this.handleClick = this.handleClick.bind(this);
  };

render () {
     return (<div><button onClick="handleClick" />{this.state.msg}</div>);
  };

// この関数内のthisは束縛されているので、何もしなければ、
ステートを変更することができない。(コンストラクタで、クラスのthisを関数に束縛している。)
  handleClick () { this.setState({ msg: "clicked"}); }; 
}

まとめ・感想

アロー関数って、省略してかける便利なやつやろ!みたいな理解でしたが、今回調べてみて、全然JavaScriptそのものに対する理解が足りていないことを実感しました。

スコープについては問題なく理解できましたが、束縛、this, argumentsなどまだまだしっかりと理解できていないことが山のようにありました。。。。

参考

MDNさん、いつもありがとう!!

#011 PHPでユニットテストをやってみた

今日も今日とて夜遅くの投稿になってしまいました。 本日は、PHPユニットテストをやってみたのでその記録です。

前回、テストの重要性を身に染みて感じたのですが、全てのテストを、手動でやるとしんどいですよね。(僕は途中からサボってしまう気がします。)

なので、テストを自動化する能力を身に付けたいと考えました。自動化できるだけではよくなくて、必要なテストを作成できること、今後の改修についていけるテストであること、改修のたびにテストコードも追従させる気持ち、なども必要でしょう。

まずは、その大前提となる、テストコードをかけるようになるというのが最初の目標です。

ユニットテストとは

ユニットテストは別名、単体テスト、ともよび、関数やメソッド単位で処理が想定通りのものになっているかを確認するテストのことです。他にも、プログラム全体として処理が正しく行われるのかを確認する結合テストというものがあります。

ユニットテストを行う際には、二つの観点からテストを行うことができます。 テスト対象のコードの中身を知っている状態でテストをするのか(中の処理に着目する、例えば条件分岐を全て網羅するなど)、中身がわからない状態でテストをするのか(入力と出力に着目する)という2つです。前者をホワイトボックステスト、後者をブラックボックステストといいます。

PHPUnitをインストールする

PHPユニットテストを行おうとすると、いくつかの選択肢があるようなのですが、今回は無難に一番有名なPHPUnitを選択しました。

# bash

$ cd 好きなディレクトリ

# PHPUnitをインストール(バージョン指定はしていない)
$ composer require --dev phpunit/phpunit

$ vim ~/.bash_profile
# 面倒なので、bash_profileにエイリアス追加
alias phpunit="./vendor/phpunit/phpunit/phpunit"

$ phpunit --version
PHPUnit 9.3.10 by Sebastian Bergmann and contributors.

$ vim ./composer.json
// phpunitのバージョンは、それぞれの環境で合わせ、以下の内容に書き換える
{
    "require-dev": {
        "phpunit/phpunit": "^9.3"
    },
    "autoload": {
        "psr-4": {
            "": "src/"
        }
    }
}

# composer の状態を更新
$ composer dump-autoload

上記のように好きなディレクトリ(プロジェクト)で、PHPUnitをインストールしましょう。 毎回、PHPUnitを実行するのに、./vendor/phpunit/phpunit/phpunitと入力するのは大変なので、エイリアスを設定しておきました。

ドキュメントによると、グローバルにインストールするのは推奨されていないようです。プロジェクトごとにいれましょう。(理由はわかっていないので、しりたい。)

簡単なテストを行う

ディレクトリ構造は、下記のような構成です。

  • src
  • tests
  • vendor/
  • composer.json
  • composer.lock
// Dog.php

<?php

class Dog {
  private $age;
  private $name;
  private $type;


  public function __construct(int $age, string $name, string $type) {
    $this->age = $this->calcAge($age);
    $this->name = $name;
    $this->type = $type;
  }

  public function calcAge($age) {
    return $age * 5;
  }

  public function getAge() {
    return $this->age;
  }
}

nameとtypeを使っておらずすみません。しかも、存在しなさそうなクラスを作成してしまい申し訳ありません。。。。まぁ、人間年齢をコンストラクタで与えると、犬の年齢に変換してインスタンスが保持するということを想定しています。

// DogTest.php
<?php

use PHPUnit\Framework\TestCase;

class DogTest extends TestCase
{
    public function test_犬の年齢に変換して保存される()
    {
        $dog = new Dog(12, "hachi", "司馬犬");

        $this->assertEquals(60, $dog->getAge());
    }
}

メソッド名の通り、入力値が犬の年齢に変換されているかを確認するテストです。 まだ、本当に簡単なことしかしていませんが、意外とすぐできました。 今回は、不要なテストを作ってしまいましたが、うまく作成できれば、非常に役立つテストになることがなんとなく理解できます。

TDDのような開発手法も、しっかりとタスクを処理できる単位に落とし込めれば、非常に力強い味方になりそうです。(まだ触り出したばかりなので、どこが優れていて、どこに難ありという知識が乏しいですが。。。)

まとめ・感想

思っていたよ理簡単にできてしまいましたが、これを開発現場でどのように利用すればよいのかまだいまいち掴めていません。うまく書き方がわかってくれば、ミスを減らす良い道具になるとは想像しているのですが、まだしっくりきていません。

次回は、もう少し

参考