フロントエンドデベロッパーのメモ

スキル: HTML/Jade/Jinja2, CSS/SCSS, JavaScript(ES6), Angular, React,Next, Redux, Node, Express, Python, Flask, Postgres, Redis, MongoDB, Kafka, Knex, SQLAlchemy, React Native, EXPO, GraphQL/Apollo, REST, AWS, Heroku, Docker, CircleCI, SCRUM, XP, Vim, TDD

Lazy Loading Images with IntersectionObserver API

恥ずかしながら今まで画像のlazy loadingをまだ試したことがありませんでした。 lazy loadingに注目したきっかけは、HTML関係で足りてない知識を補強しようとフロントエンド向け面接対策を解いてた時に発見したからです。

ちなみにフロントエンドとして働こうと思ってる人はここで知識の補完のために参考にしてみてはいかがでしょうか。 GitHub - yangshun/front-end-interview-handbook: 🕸 Almost complete answers to "Front-end Job Interview Questions" which you can use to interview potential candidates, test yourself or completely ignore

なぜLazy Loading Image? 理由は2つあります。1つは、ユーザーがページを開いても文章などを最後まで読まずに離脱する場合があります。こういった場合にユーザーのメモリ、バッテリーの消費を防ぐためです。2つめは、軽量な画像を最初にロードさせることでレンダリングスピードを改善することが可能だからです。SEOやってる方ならこの方法で直帰率の改善要因としても考慮することができます。

Lazy Loadingの例 もしあなたがMediumの読者であれば、文章をスクロールしていく間にぼやけた画像が後からくっきりした画像に替わるのをみたことがあるかもしれません。 あれは、あらかじめにデータサイズの小さい画像をセットして置いて、JavaScriptでスクロール位置を検知させることで画像を貼り替えてるんですね。 簡単な例を作ってみました。 codepen.io 他にもresizeやsetIntervalを使った方法もあります。 ただこれらの方法だとパフォーマンスに関して2つ問題があります。 1つ目は、上のPENではremoveEventListenerを設定していますが、せずにリスリングさせると常に関し状態となってメモリ食います。 2つ目は、reflowしてしまいます。

これらの問題を解決するためにたくさんライブラリがリリースされていますが、今回は新しいブラウザAPI Intersection Observerがリリースされていたのでそれを試してみました。この記事作成時点で更新が6日前で更新が頻繁に行われているようです。

Intersection Observerを使用すると今まで必要だったハンドラーの設定や、何ピクセルでどのようなアクションをトリガーするといった詳細設定が不要になります。これらの煩雑な設定の代わりにするべきことは、画像が見えるようになった時点で何をしたいかを設定するだけです。 この画像が見えるようになった時点と言うのも「何%見えるようになった時点」にしたいかを0.0から1.0の間で設定可能です。

基本的な形は以下です。

const observer = new IntersectionObserver(callback, options);

optionsの条件を満たした時点でcallbackを発火させます。 optionsは以下の3つを指定します。

const options = {
    root: null, //default is null, but you can specify the ancestor of the target
    rootMargin: '0px',
    threshold: 1.0 // specify between 0.0 and 1.0
}
  const callback = function(entries, observer) {
    entries.forEach(function(entry) {
//Do something awesome
    });
  };

observerの設定が完了したらあとは、あとは監視したいターゲットを設定するだけです。

const target = document.querySelectorAll("img") // targets that you want to make actions.
observer.observe(target);

PENで簡単な例を作って練習してみました。

参考資料

developer.mozilla.org

developers.google.com

codepen.io

Cookieにブラウザの表示回数をセットしてみた。

以前にCookieを使って簡単なゲームを作ってみたのでここにコードを残しておきます。 本当はPlunkerとかに保存できたらと思ったんですが、画像を保存したりサブフォルダ作ったりできなかったので諦めました。 このゲームを作った時の条件は以下の通りです。

  • ユーザーは風船とページの訪問回数をみることができる。

  • 風船の色は赤と青の二色がある。

  • ユーザーが初めてページを開いた時は、50:50の確率でランダムで風船の色が選択される。

  • 二回目以降は、前に選択された風船と同じ色を表示する。

  • 表示回数と風船の色についての情報はlocalStrageを使わずにcookieに書き込む。

package.json

{
  "name": "balloon",
  "version": "1.0.0",
  "main": "server.js",
  "license": "MIT",
  "scripts": {
    "start": "nodemon node server.js",
    "test": "mocha"
  },
  "dependencies": {
    "express": "^4.16.3",
    "nodemon": "^1.18.3",
    "path": "^0.12.7"
  }
}

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Welcome!!</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    <div id="report">
        <p id="color"></p>
        <p id="times"></p>
    </div>
    <div id="remove">
        <span id="remove-message">Click & Remove your Cookie</span>
    </div>
    <div class="balloons"></div>
    <script src="https://cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>
    <script type="text/javascript" src="./app.js"></script>
</body>

</html>

style.css

body {
  display: flex;
}

#report {
  display: flex;
  width: 100%;
  height: 50px;
  border: 5px solid #333;
  border-radius: 5px;
  justify-content: center;
  align-items: center;
  z-index: 1;
}

p {
  text-align: center;
  font-size: 50px;
}

#remove {
  position: fixed;
  height: 100px;
  width: 100px;
  right: 10px;
  bottom: 110px;
  border: solid 5px green;
  border-radius: 50%;
  background: green;
}

#remove-message {
  position: absolute;
  top: 25%;
  color: #fff;
}

.balloons {
  position: fixed;
  width: 100%;
  height: 250px;
  -webkit-animation: moveup 5s linear;
  animation: moveup 5s linear;
  opacity: 0;
}

@-webkit-keyframes moveup {
  0% {
    bottom: 0%;
    opacity: 1;
  }
  100% {
    bottom: 100%;
    opacity: 0;
  }
}
@keyframes moveup {
  0% {
    bottom: 0%;
    opacity: 1;
  }
  100% {
    bottom: 100%;
    opacity: 0;
  }
}

server.js

const express = require("express");
const path = require("path");
const app = express();
app.use(express.static(__dirname + "/"));
app.get("/", (req, res) => res.sendFile(path.join(__dirname, "./index.html")));
app.listen(3000, () => console.log("Listening on port 3000!"));

app.js

/**
 * Initialise a function to render a balloon and report
 */
function init() {
  // get a cookie information
  let cookie = decodeURIComponent(document.cookie);
  // if a user does not have a cookie set cookie with chosen balloon color
  if (cookie.length === 0) {
    // judge the initial value with a random value to select a balloon color
    const val = Math.random();
    let balllonColor = chooseBalloon(val);
    // set user information in cookie with the following information
    // the balloon color, the number of times user opened the page
    setCookie("color", balllonColor);
    setCookie("times", 1);
    // record how many times a user has seen each color of ball
    // provide a report on users and number of times they saw each color ball
    setTextInReport(balllonColor, 1);
    renderBalloon(balllonColor);
  } else {
    // get a cookie and,
    //  the next time a user visits the page show the same color ball they saw previously
    const balllonColor = Cookies.get("color");
    let times = parseInt(Cookies.get("times"));
    times += 1;
    setCookie("times", times);
    setTextInReport(balllonColor, times);
    renderBalloon(balllonColor);
  }
  // remove a cookie
  const removebtn = document.getElementById("remove");
  removebtn.addEventListener("click", removeCookie);
}

/**
 * Render a balloon with a given color
 * @param {String} color
 */
function renderBalloon(color) {
  // get balloon id
  const balloon = document.querySelector("div.balloons");
  // balloon color path
  const bcp = color === "red" ? "./images/red.jpeg" : "./images/blue.jpeg";
  let i = 1;
  while (i < 13) {
    const img = document.createElement("img");
    img.setAttribute("src", bcp);
    img.setAttribute("width", "304");
    img.setAttribute("height", "228");
    balloon.appendChild(img);
    i++;
  }
}

/**
 * Choose a Balloon color
 * @param {Number} num
 */
function chooseBalloon(num) {
  let color = "";
  // if the val is bigger than 0.5, then a user will see a red balloon image
  // otherwise a user will see a blue balooon image
  color = num >= 0.5 ? "red" : "blue";
  return color;
}

/**
 * Set a cookie
 * @param {String} name
 * @param {Number} val
 */
function setCookie(name, val) {
  Cookies.set(name, val, { expires: 7, path: "" });
}

/**
 *  Set texts in a report
 * @param {String} color
 * @param {Number} nums
 */
function setTextInReport(color, nums) {
  const ucolor = document.getElementById("color");
  const unums = document.getElementById("times");
  ucolor.style.color = color === "blue" ? "blue" : "red";
  ucolor.innerHTML = `This is your color, ${color}!`;
  unums.innerHTML = `You visited this page ${nums}!!`;
}

/**
 * Remove cookie
 */
function removeCookie() {
  Cookies.remove("color");
  Cookies.remove("times");
}

// Trigger the init function
init();

gif画像載せようとしましたけど、ブログサイトのメモリ容量的に厳しいみたいなのでありません。 上記のコードをコピペして、風船の画像をimagesディレクトリに保存して、yarn (or npm install)後のyarn start or(npm run start)したら http://localhost:3000/ で雰囲気が伝わると思うので興味がある方は試してみてください。

Observableってなに?in JS

最近ReduxのソースコードやMobXのドキュメントを読んでると当然のようにObersevableというキーワードを見かけるようになったのでObservableとはなんぞやということで少し調べてみました。少しだけ調べた結果から言うと、ES7(ES2016)のシンタックスとして追加されると言われていたりObersevableはAPIなのでシンタックスとしては追加されないなど余計にややこしくなりました。と言うことで、公式プロポを確認した結果ありました。こちらにスタンダードライブラリとして紹介されています。

github.com

ちなみにさっきのリンク読めば書いてるんですけど、Observableのライブラリは他にも3つあります。 個人的に一番とっつきやすいのかなと思ったのは、 https://github.com/staltz/xstream

王道は行くなら https://github.com/ReactiveX/RxJS

こちらは、プロポの共著者の方が書いてるらしいですね。 https://github.com/zenparsing/zen-observable

どれが良いかと言われると正直決めかねますから、どれも使いこなせると一番良いのかもしれません笑 ただ基本的なコンセプトは同じなのでどれか一つやっておけば、ここで紹介した他のライブラリをチーム内で使用することになってもすぐ適応できるはずです。

ところで、Observableを作った理由ですがドキュメントによると、

ユーザーによるDOMイベントが発生した時(例えばボタンがクリックされたなど)にストリーム処理をプラットフォーム内やアプリケーション内で共有することができます。なぜこんなことをする必要があるのかと言うとJavaScriptのそれぞれのライブラリやフレームワーク間で使用しているキーワードが被ってしまい、想定していなかったイベントが起こってしまうといった不都合が起こってしまうためです。

具体的な使用例については後日改めて記載したいと思います。

最近の転職活動について振り返ってみました。

ここ数日スケジュール調整、面接やコーディングテストばかりが続いてブログ書いてる暇が全くありませんでした。 メインとしている企業は、受託開発会社は受けず、自社サービス・プロダクトを開発している企業です。 外資系メインで受けていますが、内資企業も面白い企業があれば受けています。 ただ外資企業は求人情報サイトには公開されていない企業が多く、独力で探すのはかなり厳しいので、リクルーター経由や知り合い経由で紹介してもらっていますね。

希望しているポジションはフルスタックですが、どちらかというとフロントエンドの方が得意です。

面接で質問されること。 会社によって全然違いますけど、特定の言語にマトを絞った会社ならメソッドについての質問。フルスタックとして当然知ってることを聞かれる場合は、OSIモデルやREST、ウェブブラウザを開いて特定のウェブサイトにアクセスするまでの詳細な説明とか聞かれました。この辺はオンラインスクールのUdacityってところで面接対策をみっちりしてくれるんで繰り返し復習しとけばなんとかなります。あとはホワイトボーディングなどのライブコーディング、忙しい会社だったら課題渡されて1週間後提出といった、まあ他の技術ブログを書いてる方たちと同じようなことですね。なので、私からシェアできる情報と言えばUdacityくらいです。外資系の企業受けたい方はとりあえずここで、どのように技術的な質問に答えるかを動画を見て真似っこして見てください。まだ転職活動中の私がこんな偉そうなこと書いてしまってますが、参考になれば幸いです。

www.udacity.com

dbuserとdbpasswordってどこにあるの?Where is my dbuser and dbpassword in MongoDB?

English is below.

MongoDBをExpress.jsで作ったAPIサーバー上で使用する際に、データベースを確立した時のMongoDB URLがデータベースにリクエストを送る時に必要になります。この時にdbuserとdbpasswordが必要になるのですが、これは一体どこからくるのか?という話です。 最初はmLabに登録した際のユーザーネームとパスワードかと思いましたが、もしそうだとするとデータベース確立するたびに同じユーザーネームとパスワードを使用することになりセキュリティ上から見ても危険すぎます。

実はdbuserとdbpasswordに関しての説明は、mLabのサイトにも記載されています。なので、一応mLabのリンクも貼っておきます。 https://docs.mlab.com/connecting/

しかしここでは、簡単にどこで情報を入手するかをご紹介します。 データベースを確立すると、mLabサイトのHOME画面にあなたのデータベースのリストがあるはずです。そのリストの中で今回使用したいデータベース名をクリックすると詳細ページにアクセスしますが、私の場合は下図のようなタブリストがあります。 https://docs.mlab.com/connecting/ このリストの中の「Users」を開くと、右手側に「Add Database user」と記載されたボタンがあります。ここをクリックすることで、お好きなdbuserとdbpasswordを設定することが可能です。

After you deployed your database in MongoDB, you can see MongoDB URI. But where is your dbuser and dbpassword? Do they mean your user and password on mLab? No no. You need to define by yourself. I referred this page by the way.

https://docs.mlab.com/connecting/

After your deployment of your database and go HOME, you can see your deployments. Click your deployment. Click Users tab at the collection of tabs: Collections, Users, Stats, Backups, Tools. f:id:morita657:20180806164730p:plain

Now you can pass your dbuser and dbpassword on your URI.

Reactのコンポーネントパターンについて。React component patterns

English version is below.

Reactのコンポーネントパターンというと色々な考え方がありますけど、大きく分けると3種類だけなのかなと考えています。 ステートなし、ステートあり、あとはコンテナコンポーネントです。 それとステートなしは2種類の書き方がありますんで、それも別々にカウントしたら4種類ですね。 ちょっと実際にどんなものがあるのか見てみましょう。

先ほどもステートなしは2種類の書き方があるといいましたけど、そのうちの一つは関数型です。シンプルで書きやすいですね。 既存のプロパティを引数として渡してあげることで、HTML要素に入れることができます。

パターン1 ステートなし(関数型)

function Hello(props) {
  return (<div>Hello, {props.name}</div>);
}

ちなみにES6で書いてあげると、

const Hello = (props) => (<div>Hello, {props.name}</div>);

こんな感じになります。

もう一つのステートなしはクラス型です。ステートありコンポーネントを書く時によくお世話になります。個人的にはこっちの方が好きです。

パターン1' ステートなし(クラス型)

class Hello extends React.Component {
  render() {
    return (<div>Hello, {props.name}</div>);
  }
}

パターン2 ステートあり 次にステート(state)ありです。 このstateの特徴ですが、クラス型でないと利用できないのと、propsに似ているもののプライベートなので、他のコンポーネントからは操作できません。 ちなみに以下の例ではstate使う必要はないんですけど、とりあえずstateの紹介ということで勘弁してください。

class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: "Taro" };
  }

  render() {
    return (
      <div>
        <h1>Hello, {this.state.name}!</h1>
      </div>
    );
  }
}

パターン3 コンテナコンポーネント

コンテナコンポーネントとはなんぞや、ということですが。やってることは単純でデータをfetchしてそのデータをサブコンポーネントに渡してるだけです。 例えば以下の例が一番シンプルでわかりやすいと思います。

class Main extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: "Taro" };
  }
  render() {
    return <Hello {...this.state} />;
  }
}

const Hello = (props) => (<div>Hello, {props.name}</div>);

まあざっとこんなところでしょう。

ちなみに、ライフサイクルとかについて触れ出すともっと面白いことがいっぱいできます。例えばreconciliationっていうV-DOMのコアになってるアルゴリズムがありますが、それはまた次回詳しくご紹介させていただきます。

So there are basically 3 patterns to declare React components in my opinion.: Stateless, Stateful, Container Component. And there are 2 ways to declare stateless component in addition. Well, let's see them one by one.

Previously I mentioned there are 2 ways to declare a stateless component. One way is functional style, and it is simple to write. In this way, you can take a property as an argument, then pass it to render method like below.

Pattern1 Stateless(functional style)

function Hello(props) {
  return (<div>Hello, {props.name}</div>);
}

You might see this with ES6.

const Hello = (props) => (<div>Hello, {props.name}</div>);

The other is classical style. This is the same style to write with a stateful component. I love this. Pattern 1' Stateless(classycal style)

class Hello extends React.Component {
  render() {
    return (<div>Hello, {props.name}</div>);
  }
}

Pattern2 Stateful Next one is a stateful component. Note In this 'state', you can only with classical style. And although it is similar to props, it is private and cannot change the data from other components. Besides, in the following example, it is unnecessary to use a stateful, but let me just use for this introduction.

class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: "Taro" };
  }

  render() {
    return (
      <div>
        <h1>Hello, {this.state.name}!</h1>
      </div>
    );
  }
}

Pattern3 Container Component WTF is container component!? It is really simple what it does. It simply fetches data, and pass it down to the sub-component. That's all. The following example is hellpful to understand.

class Main extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: "Taro" };
  }
  render() {
    return <Hello {...this.state} />;
  }
}

const Hello = (props) => (<div>Hello, {props.name}</div>);

That's all this time. Looks easy to understand? I hope so. And once we dive into React's lifecycle, there are a lot of fun! For example, taking a look about a reconciliation that is the core algorithm of V-DOM, you might have a lot of aha moments! Well, let's dive into it next time.

Resources:

reactjs.org

www.youtube.com

Component Types | React FAQ

The difference between European Roulette and American

const rouletteFunc = (src1, src2, num) => {
  return countDifference(makeList(src1, [], num), makeList(src2, [], num));
}

const makeList = (listSource, list, N) => {
  let sliced;
  for (let i = 0; i < listSource.length; i++) {
    if (i + N > listSource.length) {
      sliced = listSource.slice(i).concat(listSource.slice(0, N - (listSource.length - i)))
    } else {
      sliced = listSource.slice(i, i + N);
    }
    list.push(sliced.reduce((total, crr) => total + crr, 0));
  }
  return list;
}

const countDifference = (EL, AL) => {
  let count = 0;
  const ELSorted = EL.sort((first, second) => second - first)
  const ALSorted = AL.sort((first, second) => second - first)
  for (let i = 0; i < ALSorted.length; i++) {
    if (ELSorted[i] < ALSorted[i]) {
      count++;
    }
  }
  return count;
}

const european = [0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 11, 30, 8, 23, 10,
  5, 24, 16, 33, 1, 20, 14, 31, 9, 22, 18, 29, 7, 28, 12, 35, 3, 26];
const american = [0, 28, 9, 26, 30, 11, 7, 20, 32, 17, 5, 22, 34, 15, 3, 24, 36, 13, 1,
  00, 27, 10, 25, 29, 12, 8, 19, 31, 18, 6, 21, 33, 16, 4, 23, 35, 14, 2];


console.log(rouletteFunc(european, american, 3));