プログラミングとSEOと暇つぶし

駆け出しエンジニアdallPのブログです。元SEOコンサルタントです。プログラミング、SEO、アフィリエイト、お金などについて役に立つかもしれない情報をやりたいように書きます。

MeteorJSとReactを勉強してみる その2: ReactコンポーネントでViewを作成しよう【公式翻訳】

Meteor公式翻訳の第二弾です。

基本的に1レッスン1記事、計12記事で書く予定です。

ReactコンポーネントでViewを定義する

アプリのViewライブラリとしてReactを利用するにあたって、まずはいくつかのNPMパッケージをインストールしましょう。 新しくターミナルの画面を開いて、前回作成したアプリがあるディレクトリまで移動して下記のコマンドを打ってください。

meteor npm install --save react react-dom

Note: meteor npmコマンドはnpmコマンドと同様の挙動をしますが、一部重要な差があります。詳細についてはmeteor npmのドキュメントを参照してください。

初期のコードを書き換えよう

手始めに、前回作成したデフォルトアプリのコードを書き換えましょう。 まず、client/main.htmlを下記のように書き換えます。

before

<head>
  <title>react-meteor-app</title>
</head>

<body>
  <h1>Welcome to Meteor!</h1>

  {{> hello}}
  {{> info}}
</body>

<template name="hello">
  <button>Click Me</button>
  <p>You've pressed the button {{counter}} times.</p>
</template>

<template name="info">
  <h2>Learn Meteor!</h2>
  <ul>
    <li><a href="https://www.meteor.com/try" target="_blank">Do the Tutorial</a></li>
    <li><a href="http://guide.meteor.com" target="_blank">Follow the Guide</a></li>
    <li><a href="https://docs.meteor.com" target="_blank">Read the Docs</a></li>
    <li><a href="https://forums.meteor.com" target="_blank">Discussions</a></li>
  </ul>
</template>

after

<head>
  <title>Todo List</title>
</head>
 
<body>
  <div id="render-target"></div>
</body>

次に、client/main.jsも下記に書き換えましょう。

before

import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';

import './main.html';

Template.hello.onCreated(function helloOnCreated() {
  // counter starts at 0
  this.counter = new ReactiveVar(0);
});

Template.hello.helpers({
  counter() {
    return Template.instance().counter.get();
  },
});

Template.hello.events({
  'click button'(event, instance) {
    // increment the counter when button is clicked
    instance.counter.set(instance.counter.get() + 1);
  },
});

after

import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
 
import App from '../imports/ui/App.js';
 
Meteor.startup(() => {
  render(<App />, document.getElementById('render-target'));
});

そうしたら、次はimportsという新しいディレクトリを作ります。 Meteorのプロジェクトにおいて、importsという名前のディレクトリは特別で、他のものとは異なる挙動をします。

importsの中にないファイルはMeteorサーバーが立ち上がると自動的にロードされますが、importsだけはimport宣言がされたときのみにロードされます。

importsディレクトリをアプリのディレクトリ直下に作成したら、その中に新しく2つのファイルを作成しましょう。

imports/ui/App.js

import React, { Component } from 'react';
 
import Task from './Task.js';
 
// App component - represents the whole app
export default class App extends Component {
  getTasks() {
    return [
      { _id: 1, text: 'This is task 1' },
      { _id: 2, text: 'This is task 2' },
      { _id: 3, text: 'This is task 3' },
    ];
  }
 
  renderTasks() {
    return this.getTasks().map((task) => (
      <Task key={task._id} task={task} />
    ));
  }
 
  render() {
    return (
      <div className="container">
        <header>
          <h1>Todo List</h1>
        </header>
 
        <ul>
          {this.renderTasks()}
        </ul>
      </div>
    );
  }
}

imports/ui/Task.js

import React, { Component } from 'react';
 
// Task component - represents a single todo item
export default class Task extends Component {
  render() {
    return (
      <li>{this.props.task.text}</li>
    );
  }
}

ここまでで3つの新しい要素をアプリに追加しました。

  1. App.js というReactコンポーネント
  2. Task.js というReactコンポーネント
  3. client/main.jsのMeteor.startupスコープに書かれた初期化文

3つめの初期化文には、ページがロードされ表示の準備が整った状態で、どのように他のコードを呼び出すかを書いています。 この初期化文は他のコンポーネントをロードし、#render-target内のHTMLとして描写します。

importsディレクトリがどのように動作するのか、そして実際にはどのような構成でアプリを作っていけば良いのか、より詳細にはApplication Structure articleを読んでみてください。

チュートリアルを進め、コードを追加・変更していく中でこれらのコンポーネントについても再度解説します。

変更結果を確認してみよう

アプリを立ち上げてブラウザを見てみると、アプリの内容が下記のように書き換わっているのが分かるかと思います。

f:id:dallP:20171216012008p:plain

もしこのようになっていなければ、このページ(訳者注: 元ページ)の各コードスニペットの右上リンクからGitHubをチェックし、自分の書いたコードが確実に例と合致しているか確認してみてください。

HTMLファイルには静的コンテンツを書く

Meteorはアプリのフォルダ内の全てのHTMLファイルを解析し、<head><body><template>の3つのタグを特定します。

<head>内の全ての要素はクライアントに送信されるHTMLのheadセクションに、そして<body>内の全ての要素はbodyセクションに追加されます。これは普通のHTMLファイルと同様です。

ただ、<template>内の全ては「Meteor template」にコンパイルされます。templateはHTML内では{{> templateName}}JavaScript内ではTemplate.templateNameで表現されます。

このチュートリアルでは、View内のコンポーネント定義には全てReactを利用するので、templateは利用しません

ReactでViewを構成する

Reactでは、ViewコンポーネントはReact.Componentのサブクラスです。 なお、このReact.Componentはimports/ui/App.jsで書いたようにimport { Component } from 'react';という宣言でインポートできます。

自分で作ったコンポーネントには好きなメソッドを持たせることができますが、renderのように特殊な機能を持つメソッドが既に存在しています。

また、コンポーネントはその親からpropという属性でデータを受け取ることができます

このチュートリアルではさらにいくつかのReactの一般的な特徴について解説していきます。詳細なReactの解説については、FacebookのReactチュートリアルを参照してください。

マークアップ(HTML)の内容はJSXのrenderメソッドでレンダリングされる

どのReactコンポーネントにおいても最も重要なのが、render()メソッドです。 そのコンポーネントは表示すべきである、というHTMLの内容を取得するためにReactによって呼び出されるメソッドがrender()です。

Reactでは、HTMLはJSXというJavaScriptの拡張構文で表現します。イメージとしては、JavaScriptファイルの中にHTMLをそのまま書く感じです。

ただし既に見たとおり、明らかに通常のHTMLと異なる点がいくつかあります。

特に理解すべきなのが、JSXではclassではなくclassName属性を用いるということです。 重要なのは、JSXはSpacebarsやAngularのようなテンプレート言語ではない、ということです。JSXはそのまま正規のJavaScriptコードにコンパイルされます。 より詳しくは、Reactのドキュメントで読んでください。

JSXはecmascriptのAtmosphereJSパッケージを利用していますが、新しいMeteorアプリの中にはデフォルトで上記が含まれています。

CSSを追加する

before

/* CSS declarations go here */

after

/* CSS declarations go here */
body {
  font-family: sans-serif;
  background-color: #315481;
  background-image: linear-gradient(to bottom, #315481, #918e82 100%);
  background-attachment: fixed;
 
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
 
  padding: 0;
  margin: 0;
 
  font-size: 14px;
}
 
.container {
  max-width: 600px;
  margin: 0 auto;
  min-height: 100%;
  background: white;
}
 
header {
  background: #d2edf4;
  background-image: linear-gradient(to bottom, #d0edf5, #e1e5f0 100%);
  padding: 20px 15px 15px 15px;
  position: relative;
}
 
#login-buttons {
  display: block;
}
 
h1 {
  font-size: 1.5em;
  margin: 0;
  margin-bottom: 10px;
  display: inline-block;
  margin-right: 1em;
}
 
form {
  margin-top: 10px;
  margin-bottom: -10px;
  position: relative;
}
 
.new-task input {
  box-sizing: border-box;
  padding: 10px 0;
  background: transparent;
  border: none;
  width: 100%;
  padding-right: 80px;
  font-size: 1em;
}
 
.new-task input:focus{
  outline: 0;
}
 
ul {
  margin: 0;
  padding: 0;
  background: white;
}
 
.delete {
  float: right;
  font-weight: bold;
  background: none;
  font-size: 1em;
  border: none;
  position: relative;
}
 
li {
  position: relative;
  list-style: none;
  padding: 15px;
  border-bottom: #eee solid 1px;
}
 
li .text {
  margin-left: 10px;
}
 
li.checked {
  color: #888;
}
 
li.checked .text {
  text-decoration: line-through;
}
 
li.private {
  background: #eee;
  border-color: #ddd;
}
 
header .hide-completed {
  float: right;
}
 
.toggle-private {
  margin-left: 5px;
}
 
@media (max-width: 600px) {
  li {
    padding: 12px 15px;
  }
 
  .search {
    width: 150px;
    clear: both;
  }
 
  .new-task input {
    padding-bottom: 5px;
  }
}

CSSを追加したので、アプリの見栄えも良くなったはずです。 ブラウザで上記のスタイルが読み込まれているか確認しましょう。


第二弾はここまでです。 どうでしょうか。僕の翻訳もごく一部自信のない部分があるので、もし間違いに気づいたら教えてくださいm( )m

第三弾は来週中にでも。

MeteorJSとReactを勉強してみる その1: 初めてのアプリを作ろう【公式翻訳】

はじめに

このエントリ及び続編のエントリでは、超若輩エンジニアがJSのフルスタックフレームワーク'Meteor'を勉強するついでに公式チュートリアルを和訳していきます。

勉強したくなった理由は名前がかっこいいからと、海外だと比較的人気のあるフレームワークみたいだからです。

大前提として自分の勉強のためであり、本エントリの活用は自由ですが、これにより生じた一切の不具合・不都合などの責任は負いませんのでご了承くださいm(_ _)m

Meteorとは

比較的新しい(とは言え初めてこの世に出たのは2012年らしい by. Wikipedia)JavaScriptのWebフレームワークです。
超簡単に言うと、超簡単にWebアプリケーションが作れるフレームワークです。

よく挙げられる特徴としては、

・高速プロトタイピングをしながらの開発が可能
・Webのみでなく、iOSAndroid向けの開発も比較的簡単にできる
・MongoDB
・データの変更を勝手にクライアントに伝達してくれる
・名前がかっこいい()

などがあります。
きっと他にも色々あるのでしょうが、一旦こんなところで。

下記から公式サイトのチュートリアル抄訳を掲載します。
日本語的わかり易さのため、ところどころ意訳します。間違っていると思ったら遠慮なく突っ込んでください。

なお、公式サイトにはいくつかのチュートリアルの種類がありますが、今回はTo Do AppのReactバージョンで進めていきます。
理由は僕がReactを勉強したいからです。

初めてのアプリを作成する

このチュートリアルでは、Todoリストを管理し、リスト上のタスクを他の人と共有できるような簡単なアプリケーションを作成します。
チュートリアルを最後まで完了すれば、Meteorの基本的な使い方とそのプロジェクト構造について、きっと理解できることでしょう。

まずアプリを作成するには、ターミナルを開いて任意のディレクトリで次のようにコマンドを打ってください。

meteor create simple-todos

このコマンドは、Meteorのアプリケーションに必要な全てのファイル(下記)を備えた「simple-todos」という名前のフォルダを作成します。

client/main.js        # a JavaScript entry point loaded on the client
client/main.html      # an HTML file that defines view templates
client/main.css       # a CSS file to define your app's styles
server/main.js        # a JavaScript entry point loaded on the server
package.json          # a control file for installing NPM packages
package-lock.json     # Describes the NPM dependency tree
.meteor               # internal Meteor files
.gitignore            # a control file for git

上記で作成したアプリを立ち上げるには、下記のコマンドを打ってください。

cd simple-todos
meteor

コマンドを打ったらブラウザを開き、 http://localhost:3000 を開いてアプリが立ち上がっているのを確認しましょう。
次のチュートリアルに移る前に、このデフォルトアプリを少しいじってみてください。
例えば、 client/main.html 内の<h1>タグで囲まれたテキストをお好きなエディタで変更してみましょう。

変更してファイルを保存すると、ブラウザで開いたページが自動的に新しい内容に更新されます。
これをMeteorでは「hot code push」と呼んでいます。

新しいJavaScriptの記法について

MeteorではECMAScript 2015 (ES6)にあるような新しいJavaScriptの記法を多くサポートしています。
もしまだこれらの新記法を使ったことが無ければ、Luke Hoban's "ES6 features"を見て、新記法に慣れておくことをおすすめします。

さて、Meteorアプリ内のファイルをいじるのに慣れたら、早速Todoリストアプリの作成に移りましょう。
もしチュートリアル内でバグやエラーを発見したら、是非GitHubにIssueを作成するか、プルリクを投げておいてください。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

やっぱコマンドまわりが見づらいので次回以降で記法を見直します。
続きは今週中に。

【日々の学び: プログラミング】同じ結果でもより良い書き方をする / 返り値にnullが入るケースを意識する

Node.jsエンジニアのdallPです。
肩書がエンジニアになってから5営業日が過ぎました。

分からないなりに初プッシュ・プルリクを出し、初マージまでこぎつけましたが、その間にもかなりのインプットがあったので、今後は自分のために不定期にまとめていきます。

今回はタイトル通り、プログラムの書き方と返り値について。
いずれもエンジニアとしてお仕事をされている方にとっては当たり前のことで、お目汚しスミマセン。

同じ結果でもより良い書き方をする

何が言いたいのかというと、実用的なプログラムを書く場合において、過程は結果と同じくらい重要視されるよ、ということです。

初めてのプルリクを出して諸先輩方にコードレビューをしていただいた際のフィードバックの殆どは、根本的にこの考え方を持ってコーディングしていれば避けられたものです。

具体例を下記で挙げています。

Array(配列)インスタンスメソッドの使い方について

ご存じの通り、Arrayオブジェクトには様々なメソッドが用意されています。
※非エンジニアの方向けに一応書くと、Arrayとは配列を扱うためのモデルのようなものです。詳しくはこちらなど参考にしてみてください。

指摘されてから初めてまともに下記ページを眺めてみたのですが、実にあらゆるケースを想定したメソッドがデフォルトで組み込まれているのですね。

developer.mozilla.org

例えば良く使われるメソッドでは下記のようなものがありますね。

push: 配列の最後に要素を追加する
forEach: 配列中のそれぞれの要素について、自分で定義した関数を逐次的に呼び出す

で、今回問題になったのは、「forEachよりどストライクなメソッドがあるのにforEachで頑張って書く」ことをしていた部分です。

やりたかったこととしては、「ある配列の中に特定の要素があるかどうかを判定する」ことです。
実は、JavaScriptのArrayインスタンスには、デフォルトで上記の処理を行ってくれる"includes()"というステキ関数が存在します。
しかしその存在を知らず、まともに使えるメソッドがforEachくらいしかなかったdallPは頑張ってそれを書いた、ということです。

ある配列の中に特定の要素があるかどうかを判定するだけであれば、forEachに限らず他の関数を利用することもできます。


JavaScriptのArrayのサンプルコード

上記を見ていただければお分かりだと思いますが、やりたいことは同じなのにも関わらず、コード量が全然違います。
書く側にとってメリットがあるのは明らかですが、読む側にとっても理解しやすい良いコードになりますね。
③より①の方が圧倒的に読みやすいです。

SQLで取得してきたデータを加工する処理について

SQLって正直面倒ですよね。
サクサク書ける人だとそうでもないのかもしれませんが、今回については必要ないデータまで取ってきて、いらない部分はプログラム側の実装で削ぎ落とす、ということをやってしまい、注意されました。

SQLでどうにかなる絞り込みは、できるだけSQL側でやる。
プログラム側での処理・加工は最低限で。

ちなみに上記の考え方でデータを取得してきたら、上記で話したArrayのコードは結局全て不要になりました笑

定数は定義された定数名で取得する

これも当たり前といえばそうなのですが、最初は定数の中身をそのままプログラムに記述してしまっていました。
これだと、もし仮にその数値が指し示すものが変わってしまった場合にコードの修正が面倒になるし、可読性も無くなるのでNG。

定数名で取得してきていれば、その定数名さえわかりやすい命名がされていれば可読性が上がります。
コード中での検索もしやすくなりますし。

結局「より良い書き方」をしてあると何が嬉しいのか

・知ってさえいればコーディングのスピードが上がる
・コードの可読性があがる、実装内容変更時にも理解しやすい
・無駄な処理を行わないので、実際にフロントで見たときの処理速度が上がる

など。他にもあるかもしれませんが、今回僕が感じたのはこの辺の部分です。

ただ、僕のように初心者がいきなり実務に入るケースだと、当然知らないメソッドや書き方も多くあるはずです。
なぜなら初学者レベルでは、具体的なユースケースすら分からないメソッドばかりだからです。

もはやこれについては実務の中で学んでいくしかないのかな、と思っています。

返り値にnullが入るケースを意識する

「より良い書き方」に比べるとだいぶ具体的なテーマですが、要は他人が書いた(= 言語に元々実装されてるものや、外部フレームワークなど全て)関数の返り値には気をつけようぜ、ということです。

今回は、SequelizeというNode.js用のORマッパーの関数の返り値に関して突っ込みが入りました。

Manual | Sequelize | The node.js ORM for PostgreSQL, MySQL, SQLite and MSSQL

Sequelizeでは、取得してきたデータは配列となっており、該当するカラムがそれぞれSequelizeオブジェクト?として要素に格納されています。
その返り値に対して、Sequelizeで元々定義されているgetメソッドを呼んでやると、中身が連想配列になります。

なので、特に何も考えずgetを使っていたところ、「返り値がnullだった場合はどうする?」という指摘を受けた、ということです。

実際調べてみた結果、もし生成されたQueryに該当するカラムがなかった場合は空配列が返ってくる仕様だったので、その可能性も加味したコードに修正しました。

僕はゲームを買っても取説を読まない人間なのですが、仕事としてプログラムを書く以上は、しっかり読むべきところは読んでおく必要があるなと実感しました。

その他

その他にも多数の学びがあったのですが、細かいことも多いので箇条書きっぽく。

JavaScriptの変数のscopeについて: varのscopeはヤバい(関数の中で定義した変数が外から参照できたりする)ので、letを意識的に使う。
Arrow関数について: できるだけfunctionではなく=>で書く (例えば function(name) {}; であれば、 name => {}; と書き換えられる)
OR演算子 (||) について: ORで繋いだ二つの条件について、仮に一つ目の条件が常にtrueとなる場合は二つ目が評価されることはない。つまり条件として書く意味がなくなる
引数について: 引数は使わないなら省略可能だが、順番は定義されている順にしか書けない。なので、仮にデフォルトで三つの引数を取ることができる関数について、二番目の引数だけ使いたい場合、三番目の引数は省略できるが一番目の引数は省略できない。
returnについて: JavaScriptでは(他の言語では知らない)、returnは関数の中にしか書けない。ついついif文の中に書いてしまい、Syntax Errorを喰らいました。

stackoverflow.com

gitの使い方について: 下記の便利なサイトを教えてもらった。branchやmergeなどの概念がわかりやすいのでこいつで勉強する。

k.swd.cc