【もりけん塾】JavaScript課題7 -ローディング実装 ①-

JavaScript

今日は、もりけん塾のJavaScript課題7 を終えて学んだことをアウトプットしていきます。

こんにちは。Webコーダーのはるです。

現在、所属している「もりけん塾」でハンズオン課題 に取り組み、レビューをいただいています。

今日は、課題7 についてアウトプットをしていきます。
(前回までのアウトプットは、こちらです。)

●課題7で学んだこと

・処理を細かく関数に分ける
・わかりやすい関数名
・Promiseの中に書けない処理
・関数のreturnについて

【もりけん塾】JavaScript課題7で学んだこと まとめ

今回、取り組んだ課題はこちらです。

説明文↓
(もりけん先生のJavaScriptハンズオン課題より)

処理を細かく関数に分ける&わかりやすい関数名

これは前回の課題6で、塾生のさえさん(@sae_prog) からレビューいただいたことです。

処理ごとにコードを関数にまとめることで、読みやすくすることができます!

このレビューを生かして、今回も関数を分けようと思いました。

最初に分けた処理
・サーバーから値(配列のデータ)を受け取る
・loadingを追加する
・loadingを削除する
・loadingを表示させる(←?ここがよくわからないままPRしました..)

 

最初にPRしたコードは以下です。
ブログ用に分けた処理のコメントアウトを追加しました。

const ul = document.getElementById("js-lists");

//サーバーから値(配列のデータ)を受け取る
function receiveData() {
 const attributes = [
  { to: "bookmark.html", img: "1.png", alt: "画像1", text: "ブックマーク" },
  { to: "message.html", img: "2.png", alt: "画像2", text: "メッセージ" }
 ];
 return attributes;
};

//loadingを追加する
function addLoading() {
 const li = document.createElement("li");
 const img = document.createElement("img");
 li.id = "js-loading";
 li.style.listStyle = "none";
 img.src = "loading-circle.gif";

 return ul.appendChild(li).appendChild(img);
};

//loadingを削除する
function removeLoading() {
 const li = document.getElementById("js-loading");
 return ul.removeChild(li);
}

//loadingを表示させる
function displayLoading() {
 return promise = new Promise(resolve => {
  addLoading();
  setTimeout(() => resolve(receiveData()), 3000);
 });
}

displayLoading().then(values => {
 removeLoading();

 const fragment = document.createDocumentFragment();

 values.forEach(value => {
  const li = document.createElement("li");
  const anchor = document.createElement("a");
  const img = document.createElement("img");

  anchor.textContent = value.text;
  anchor.href = `/${value.to}`;
  img.src = value.img;
  img.alt = value.alt;

  li.appendChild(anchor).insertAdjacentElement("afterbegin", img);
  fragment.appendChild(li);
 });
 ul.appendChild(fragment);
});

最後の「//loadingを表示させる」以下の部分がわかりにくいし、displayLoading()の命名が違うなぁと悩み.. 懸念点に書いてPRしました。

この点に関して、塾生のmatsuさん(matsuwork_log)からレビューをいただきました。

・この関数の役割は、ローディング画像を表示することではなく、データを取得すること
・さらに「それ以降の処理のコード」を関数にして分離する

という内容でした。ありがとうございます🙇‍♀️

こちらのレビューを受けて、

・悩んでいたpromiseの処理部分の関数名を、displayLoading()からfetchListData()に変更。

・以降の処理のコードを、addList(values)として新たに関数を書きました。

ご提案いただいた関数名の中の”fetch”は、取得という意味でした。
とてもわかりやすい関数名になりました✨

また、一つの関数の中でたくさんの処理を書くととても読みにくく、適切に小さな処理に分ける大切さを学びました。ありがとうございます!

Promiseの中に書けない処理

同じくmatsuさん(matsuwork_log)にご指摘いただいて、とても勉強になったのがpromiseに書けない処理についてです。

最初私は、promiseの処理の関数を以下のように書きました。

//loadingを表示させる
function displayLoading() {
 return promise = new Promise(resolve => {
  addLoading();
  setTimeout(() => resolve(receiveData()), 3000);
 });
}

new Promiseでpromiseの処理を書き始めてから最初にaddLoading()という関数を含めています。

addLoading()はLoading用の<img>を追加するフロントの処理です。

しかし、promiseはサーバーサイドの処理をするオブジェクトなので、ここにaddLoadind()を含めてはいけませんでした。

//loadingを表示させる
function displayLoading() {
 addLoading();
 return promise = new Promise(resolve => {
  setTimeout(() => resolve(receiveData()), 3000);
 });
}

addLoading()をpromiseに含めない形に修正しました。

配列データを受け取る関数・・・?

最初に書いた

//サーバーから値(配列のデータ)を受け取る
function receiveData() {
 const attributes = [
  { to: "bookmark.html", img: "1.png", alt: "画像1", text: "ブックマーク" },
  { to: "message.html", img: "2.png", alt: "画像2", text: "メッセージ" }
 ];
 return attributes;
};

サーバーからデータを受け取る関数について、Nariさん(@weegie_design)からレビューをいただきました!

すでにconstで配列を定義しているので、returnとして返す必要はないのでは、というご指摘でした。

問題文の「サーバーから値が渡ってくる」という部分を関数化したかったのでこのように書きましたが、自信がなかったのでご指摘ありがたいです!

const attributes = [
 { to: "bookmark.html", img: "1.png", alt: "画像1", text: "ブックマーク" },
 { to: "message.html", img: "2.png", alt: "画像2", text: "メッセージ" }
];

私も全く意味のない関数だと思ったので、結果constのみにしました。

関数のreturnについて

matsuさん(matsuwork_log)にいただいたレビューの部分です。

以下の関数のreturnは、戻り値を使用していないため必要がないとご指摘いただきました。

//loadingを追加する
function addLoading() {
 const li = document.createElement("li");
 const img = document.createElement("img");
 li.id = "js-loading";
 li.style.listStyle = "none";
 img.src = "loading-circle.gif";

 return ul.appendChild(li).appendChild(img);
};

関数について理解が甘く、returnを使用することで処理を行った結果を返して、その結果を使用してさらに別の処理を行うことができるということがわかりました。

逆にreturnがない場合は、処理を行ったらそれで終了します。

今回ご指摘いただいた、関数addLoading()・removeLoading()は、処理のみの関数だったのでreturnは不必要だと理解できました。ありがとうございます

 

最終的にこのようなコードになりました。

const ul = document.getElementById("js-lists");


const attributes = [
 { to: "bookmark.html", img: "1.png", alt: "画像1", text: "ブックマーク" },
 { to: "message.html", img: "2.png", alt: "画像2", text: "メッセージ" }
];


function addLoading() {
 const li = document.createElement("li");
 const img = document.createElement("img");
 li.id = "js-loading";
 li.style.listStyle = "none";
 img.src = "loading-circle.gif";

 ul.appendChild(li).appendChild(img);
};

function removeLoading() {
 const li = document.getElementById("js-loading");
 ul.removeChild(li);
}


function addList(values) {
 const fragment = document.createDocumentFragment();

 values.forEach(value => {
  const li = document.createElement("li");
  const anchor = document.createElement("a");
  const img = document.createElement("img");

  anchor.textContent = value.text;
  anchor.href = `/${value.to}`;
  img.src = value.img;
  img.alt = value.alt;

  li.appendChild(anchor).insertAdjacentElement("afterbegin", img);
  fragment.appendChild(li);
 });
 ul.appendChild(fragment);
};

function fetchListData() {
 addLoading();
 return promise = new Promise(resolve => {
  setTimeout(() => resolve(attributes), 3000);
 });
}

fetchListData().then(values => {
 removeLoading();
 addList(values)
});

最初のコードに比べて、特に後半が何をしているのかわかりやすいコードになったと思います!

//

学習に使用している本は、もりけん先生推奨の”JavaScript本格入門”です。

あとがき

お忙しい時間を割いて課題を確認してくださった塾生のmatsuさん(matsuwork_log)・Nariさん(@weegie_design)ありがとうございました!!

私の課題のリポジトリはこちらから確認できます↓

 

今日は以上です。

//

【もりけん塾で勉強しています】

もりけん先生(@terrace_tec)のHPはこちら