manmanrai’s diary

勉強記録ブログ

React.jsもくもく会参加してみました(ほぼ雑談)

昨日はじめてReact.jsのもくもく会参加してみました。
場所はYahooのコワーキングスペースです。
恐らく百人以上余裕で入れるスペースなんですが、朝からものすごく混雑していました。

実際の状況はどうだったかというと

React.js勉強しはじめて、日がまだ浅い、全員はじめましてという状況でもあり、 このもくもく会で同じ初心者に出会えるのかなという小さな願いを抱えて臨みました。

(多分どうでも良い)発見

→自分と同じく脱jQueryという目標に向かってる人いた
→なぜか起業家が多い(やはりideaあったらすぐ実現する(させる)のが大事!)
→なぜかアメリカ留学経験持ちの方多い
→皆やりたいことはっきりしている(当たり前かもしれません、、)

(多分どうでも良い)感想

→入り早々自分もしかして軽くコミュ障疑惑浮上(自分から発言しないのかい)
→自己紹介噛んでなかったことにやや自慢できるんじゃないかと思った(レベル低すぎ)
→皆レベル高すぎ、聞いたこと無い単語の多発によりさらにコミュ障発作(正直心折れた)
→ランチ会でちょっとした雑談できたこと自分に誇りを持った(自分に甘い)

最後に

メモ:
1. redux
React Redux
Redux ExampleのTodo Listをはじめからていねいに(1)) 2. puredux
もうReduxで疲弊しない。Pureduxで始めるRedux。
3. Flux
React & Flux入門
10分で実装するFlux
【React.js】Fluxの概念を勉強するときにとっても役に立った記事まとめ
ReactとFluxとReduxについて順を追って整理する

今までReact.jsというキーワードで検索したらよくセットで出てくるものがいっぱいありましたが、実はまだ一つの触れてませんでした。
今作りたい機能について質問した時にreduxをおすすめされましたので、まずそこからはじめたいと思います。
多分それぞれに大事な概念が含まれてると思いますので、焦らずにゆっくりじっくり勉強していきたいと思います。(実は結構せっかち)
開催者のにしむらさん、 初心者の私も優しく答えてくださって、誠にありがとうございました。

次回お会いした時、皆の話ちょっとでも理解できるようになりたいです。
頑張ります。

React.jsで簡易todo listを作ってみた(codepen, github)

プロローグ

React.js公式サイト(英語)

一通りReact.jsのDocumentのinstallationとquick startを実践しながら勉強しました。
実際に自分どこまで理解できたのか知りたいので、簡単なWeb applicationを作ってみようかなと。
初心者向けの課題によく出て来るtodo listを選びました。

この記事の最後に完成したサンプル(codepen)とgithubのリンク貼り付けておりますので、ご参考にしていただければ幸いです。

要件定義

簡易バージョンなので、最低限のものだけ作りたいと思います。
- 書き込める場所
- 保存するボタン
- Todo Listを表示させる
(修正不可、削除不可)

ゴール:

完成したtodo list

参考サイト(英語)

1. Simple React todo list – Agata Krzywda – Medium

今回の勉強記録はこの記事の内容を整理しつつ、公式サイトと見比べながら書き換えたものになります。

スタート

(ターミナルで)
tutorialでインストールしたReactのcreate-react-appコマンドを使って、todolistフォルダを作成します。

$ create-react-app todolist

フォルダ内に移動します。

$ cd todolist
$ npm start

自動的にローカルでブラウザ立ち上がり、React.jsページのデフォルトの状態が表示されます。

そして、エディターでフォルダを開くと、構造は
-node_modules/
-public/
-src/
-package-lock.json
-package.json
-README.md
になっています。

/src/app.js
/src/index.js
デフォルトの書き方は主に記述内容はapp.js内で書いて、index.js内でapp.jsを呼び込んで、/public/index.html内で描きます。

実行されるものはindex.jsなので、今回はapp.jsを使わずに、index.jsだけ使いたいと思います。

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

いらないものを削除して、これだけ残します。
そして、app classをimportの後に追記します。
formを作って入れます。

import React from 'react';
import ReactDOM from 'react-dom';

class App extend React.Component {
    render() {
        return(
            <div>
                <form>
                    <input type="text" value="" />
                    <input type="submit" value="Submit" />
                </form>
            </div>
        );
    }
}

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

Appの構造を定義します。

   constructor(props) {
        super(props);
        this.state = {
            term: '',
            items: []
        };
    }

そして、functionは2つあります。
onChangeはinput内に書いたら、inputのvalueに保存する→[term]
onSubmitは先ほど保存したvalueをstate内のitemsにパスする→[items]

constructor内でfunctionを結びついてから、functionを書きます。

   constructor(props) {
        super(props);
        this.state = {
            term: '',
            items: []
        };

        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }

    onChange(e) {
        this.setState({
            term: e.target.value
        });
    }

    onSubmit(e) {
        e.preventDefault();
        this.setState({
            term: '',
            items: [...this.state.items, this.state.term]
        });
    }

...this.state.items
という書き方はquick start内には説明してなかったけど、advanced guide内にはありました。

JSX In Depth - React

すべての〇〇という意味です。ここはすべてのthis.state.itemsです。

そして、renderで書いてたform内のfunctionと繋げます。
formの書き方こちらを参照してます。

Forms - React

   render() {
        return (
            <div>
                <form onSubmit={this.onSubmit}>
                    <input type="text" value={this.state.term} onChange={this.onChange} />
                    <input type="submit" value="Submit" />
                </form>
            </div>
        );
    }

最後、todo listを表示するために、functionを作ります。
mapの書き方こちらを参照してます。

Lists and Keys - React

function List(props) {
    const items = props.items;
    const listItems = items.map((item, index) => 
        <li key={index}>
            {item}
        </li>
    );
    return(
        <ul>
            {listItems}
        </ul>
    );
}

class App内のreturnをを追記して、this.state.itemsと繋げます。

   render() {
        return (
            <div>
                <form onSubmit={this.onSubmit}>
                    <input type="text" value={this.state.term} onChange={this.onChange} />
                    <input type="submit" value="Submit" />
                </form>
                <List items={this.state.items} />
            </div>
        );
    }

最終的にまとめてみると、こうなります。

import React from 'react';
import ReactDOM from 'react-dom';


function List(props) {
    const items = props.items;
    const listItems = items.map((item, index) => 
        <li key={index}>
            {item}
        </li>
    );
    return(
        <ul>
            {listItems}
        </ul>
    );
}


class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            term: '',
            items: []
        };

        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }

    onChange(e) {
        this.setState({
            term: e.target.value
        });
    }

    onSubmit(e) {
        e.preventDefault();
        this.setState({
            term: '',
            items: [...this.state.items, this.state.term]
        });
    }

    render() {
        return (
            <div>
                <form onSubmit={this.onSubmit}>
                    <input type="text" value={this.state.term} onChange={this.onChange} />
                    <input type="submit" value="Submit" />
                </form>
                <List items={this.state.items} />
            </div>
        );
    }
}


ReactDOM.render (
    <App />,
    document.getElementById('root')
);

ブラッシュアップ

テストで何件タスクを入れてみましたが、改善点を見つけました。
例えば、間違えてenter(return)を押したら(=submitボタンを押したら)、空白のままでリストに入っちゃうので、それをブロックしたいです。

最後に空白なら追加しないようにonSubmit functionに条件入れます。

   onSubmit(e) {
        e.preventDefault();
        if(this.state.term){
            this.setState({
                term: '',
                items: [...this.state.items, this.state.term]
            });
        }
    }

これで間違えて押しても追加されません!

Todo Listの完成体はこちらです!

(はじめてCodepenを導入してみました!)

See the Pen Todo list made by React.js by manmanrai (@manmanrai) on CodePen.

Githubソースコードアップしました。
ディレクトリやファイルほぼデフォルトのままです。手入れたファイルはindex.jsのみになってます。

github.com

Babelインストールからコンパイル実行するまで

ES2015の基準に合わせたJavaScriptを書きたいと思いまして、
Babelというコンパイラを導入してみたいと思います。

公式サイト

babeljs.io

環境

mac 10.13.2

手順

  • npmでインストールしますので、まずnode.jsの生存を確認する
$ npm --version
> 3.10.10

バージョンが出たら、存在しているということですね。
Babelの公式サイトによると、npm2.Xではなく、npm3.Xでインストールするのがおすすめらしいです。

Note: Running a Babel 6.x project using npm 2.x can cause performance problems because of the way npm 2.x installs dependencies. This problem can be eliminated by either switching to npm 3.x or running npm 2.x with the dedupe flag.

  • 該当のフォルダに移動し、フォルダ初期化する
$ npm init

ここでプロジェクト名やバージョンなど案件の詳細を聞かれます。終わったら、「package.json」が生成され、先ほど聞かれたものjson形式で記載されてます。
もしこのインストールは練習用であれば、ずっとenter(return)を押し続けても大丈夫です。デフォルトか空白になります。

もしくは、素早く初期化して、デフォルトpackage.jsonも生成できるコマンド叩きます。

$ npm init -y
  • フォルダ内でBabelをインストールする
$ npm install babel-preset-env --save-dev

無事にインストールできたら、「node_modules」というフォルダが生成されます。

ここ注目して頂きたいのは「babel-preset-env」です。
babel-preset-envはES2015基準でコンパイラには必要なパッケージ全部入ってる便利なライブラリーだそうです。

  • .babelrcに関して

.babelrcという(隠し)ファイル(記述はjson形式)はコンパイルする時に参照する設定を入れる場所です。
コマンドで.babelを作成します。

$ touch .babelrc

そして、env使うので、関連な記述を入れます。

{
  "presets": ["env"]
}

ウェブサイトに応用することにあたって、対応するブラウザのバージョンに関して詳しく指定できるみたです。
例えば最新の2つバージョンとsafari7以上に対応するとか。

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ]
}

公式サイトに対応できる範囲を詳しく書いています。

Env preset · Babel

「babel-cli」というライブラリーをインストールします。
このライブラリー入れることでコマンドでコンパイル実行できるようになります。

$ npm install babel-cli --save-dev

※package.jsonの中身を確認してみると、

{
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-preset-env": "^1.6.1"
  }
}

envとcliに関する記述があれば大丈夫だと思います。

  • テストしてみよう

テスト用のindex.jsを作って、コマンドでコンパイル実行します。

$ ./node_modules/.bin/babel index.js

これ実行したら、ターミナルにコンパイルされたものが表示されたら、Babel無事にインストールできたということです!

ネットで色んな記事は大体この辺で終わりますが、いっぱい検索した方も気づいたかもしれません。凄く短いコマンドで使ってらっしゃる方もいますね。
しかし、今までの手順でやってきたので、何故かbabelコマンドで叩いてもNot foundで返って来ます。

$ bable index.js
> -bash: babel: command not found

違いはどこにあるのか、何回も読み返して判明しました。
グローバルインストールした場合には短いコマンド使えそうです。
つまり、最初のインストールは-g入れてます。

$ npm install --global babel-cli

公式にはローカルインストールの方がおすすめしてるみたいで、理由は下記になります。

While you can install Babel CLI globally on your machine, it’s much better to install it locally project by project. There are two primary reasons for this. 1. Different projects on the same machine can depend on different versions of Babel allowing you to update one at a time. 2. It means you do not have an implicit dependency on the environment you are working in. Making your project far more portable and easier to setup.

CLI · Babel

上記の2つの理由特に気にしなければ、グローバルインストールでも問題ないと思います。

今回はグローバルではないので、何とか短いコマンド使いたいですね。
公式サイトにおすすめされたnpxというパッケージを使えば、コマンドは劇的に短縮できるようで、npxについて調べてみました。

qiita.com

なるほど、npmを5.2.0以降のバージョンにアップグレードしたら使用可能みたいですね。
最初にBabelインストールする時に確認した時に

$ npm --version
> 3.10.10

node.jsのバージョンリリース早見表はこちら

リリース一覧 | Node.js

  • npmをアップグレードする

今回はこの記事を参照させて頂きました。

qiita.com

$ npm update -g npm

無事にアップグレードし、npxも入ってるようで、

$ npx babel index.js

このコマンドでコンパイル実行されました!!前より短く使えやすくなりました。

  • 別ファイルとして書き出す

同じ階層ならこんな感じで書きます。

$ npx babel index.js --out-file index2.js

--out-file → -o 置き換え!

別フォルダも大丈夫です。

$ npx babel ./src/index.js --out-file ./lib/index.js

もしくはフォルダごとコンパイルしたいなら。

$ npx babel src --out-dir lib
> src/index.js -> lib/index.js

--out-dir → -d 置き換え!

監視して欲しいなら。

$ npx babel src --out-dir lib --watch
> src/index.js -> lib/index.js

--watch → -w 置き換え

  • 【補足】コマンドではなくて、scriptでのコンパイルやり方

コマンドをpackage.jsonのscriptに入れる方法もあります。
この記事を参照させて頂きました!

qiita.com

この記事通りやってみて、分かったことが2つあります!

  1. .babelrcいらない
  2. package.json内のコマンドはbabelで書く(npxがなくても大丈夫)

こちらも良さそうですね。

自分にとって、今回のインストールとても勉強になりました。
いつも通りやりながら書きましたが、今回わからないことが多くて、結構時間かかりました。
これからもこうやって知識どんどん増やしていきたいと思います。

現在の仕事に合わせた開発環境(2017/06時点)

現在の仕事

記録のために、この記事を書きたいと思います。
今は(採用、広告)制作会社に勤めています。仕事は、大体静的なページが多いです。
例えば会社のコーポレートサイトや新卒採用サイトなど、広告寄りのサイトはランディングページなど単発なお仕事がメインです。

更新する部分が少ないため、ほぼフロントエンド側で完結できるな案件です。 ページ数もそんなに多くありません。多いときはせいぜい10ページから20ページぐらいです。

フロントエンドを極めたいなら、恐らくほとんどの方正確性や効率化を追求し始めるでしょう。 もう単純なhtml,css,javascriptを書くのは効率が悪く感じられるではないかなと思うでしょう。

そこでコンパイル必要な環境を構築し始まります。 codepenでpug,scss,sass,perl,typescriptなど便利なもの使ってらっしゃる方々よく見かけますね。

SASS

公式サイト:

Sass: Syntactically Awesome Style Sheets

最初に注目したのはsassでした。 cssって、ファイル長くなりがちなので、デザイナーさんから貰ったデザインデータたまにフォントサイズが違ったりしますので、 それで同じサイトなのに、そこでバラツキなったの個人的に気持ち悪くて、品質管理のところでも力なれたらいいなと思いまして、sassも使い始めました。

変数が使えるのがとても便利です。
extendやmixiなど機能も使えます。同じサイトで細かい色やサイズ揃えたい時(統一感)すごく助かります。
そして、一気にコードを圧縮してくれるの、そのままファイルサイズも軽くなれるのかなり良いかなと思いました。

PUG

公式サイト:

Getting Started – Pug

次はpugです。 例えば納品前の段階で全htmlファイルにある部分変更したら、いちいち手作業で変更しなければなりません。 そこでミスしたら、よく見落としたりして、本番にアップされても気づくまで結構時間経つし、 後でクレームなりやすい、リスク背負うことになるじゃないかなと思います。

もちろん、解決方法色々あると思うですが、 例えばssiとか、良いサーバーで使えるなか助かるのですが、結局お客さん側のサーバーに頼ることになって、必ずできるの保証がありません。
pugのincludeとかほぼssiと同じ感覚で、変数など使った、if elseなど使ってページよって違うもの入れるこのもできます。 すごく便利だと思います。

まとめ

多分、ここまで来たら、どうしてglupなど全自動化なもの使わないだどう疑問持ったりするかもしれません。 確かにglup使ったら画像圧縮やjs圧縮など面倒なこと一気にやってくれるだと思いますが、ただ、最初にも申し上げましたが、うちの会社の案件本当にページ数少なすぎて、そこまで開発環境を整ってから、開発スタートするのも時間もったいないと思っております。

現状はpug,scss,javascript/typejavascriptさえあれば、すぐコーディング始める手軽バージョンが今の自分んにとってのベストかもしれません。 今使ってるパソコンは一応glupの環境も作れますが、未だに出番がなかったです。 自分には必要がないと判断しましたが、10ページのサイトでもglupを導入する方社内には二人にもいます。どっちが正解、不正解なんかないから、コーディングする自体って、結構各自のスタイルありますし、もしかして、自分はただglupなど全自動コンバイラーの良さ分かってないだけかもしれないですね。

そういう機会あったら、大型案件と出会ったら、使ってみたいと思います。
これからも技術と共に一緒に進化し続けたいと思っております。