つくる 作品データを API から読む
このレッスンで分かること
- 通信、待ちの表示、失敗の表示、絞り込み、並び替えを 1 枚にまとめられる
- データの流れを「取る」「選ぶ」「描く」の 3 段に分けて書ける
- 手で書いた配列を消しても、同じ画面が出せると確かめられる
- 作品ギャラリーが、外のデータで動く状態まで進む
つくる 作品データを API から読む とは
第9章でやってきたことを、ポートフォリオの作品ギャラリーに全部つなぎます。手で書いていた作品の配列を消し、API から取ってきたデータで同じ画面を出します。
ここまでで何ができるようになったか
第9章の 4 本で、次のことを覚えました。
| 覚えたこと | 使う場所 |
|---|---|
fetch と 2 回の await | データを取ってくる入口 |
?delay=800 で待ちを再現する | 読み込み中の表示を確かめる |
response.ok と throw | 失敗を自分で判定する |
catch で画面に出す | 利用者に失敗を伝える |
JSON.stringify と送り先の決めかた | 送る側の組み立て |
そしてもっと大事なことがひとつあります。描画のコードは何も変わらなかったという事実です。第8章で書いた renderWorks は、配列をもらってカードを並べるだけの関数でした。だから、配列の出どころが手書きから通信に変わっても、書き直す必要がありませんでした。
「変わるところ」と「変わらないところ」を分けて書いておくと、あとから来る変更に強くなります。今回は出どころだけが変わりました。
取る、選ぶ、描く の 3 段に分ける
この回で書くコードは、次の 3 つの役割に分かれます。ひとつの関数に詰め込まず、分けたまま組み立ててください。
// 1. 取る。通信のことだけ知っている
async function loadWorks() { /* ... */ }
// 2. 選ぶ。配列をもらって配列を返すだけ
function selectWorks(works) { /* ... */ }
// 3. 描く。配列をもらって画面を書き換えるだけ
function renderWorks(works) { /* ... */ }真ん中の「選ぶ」が今回の新顔です。公開されている作品だけを残し、表示回数の多い順に並べます。第2章で書いた filter と sort がそのまま使えます。
function selectWorks(works) {
return works
.filter((work) => work.published)
.sort((a, b) => b.views - a.views);
}sort は元の配列を並べ替えてしまう破壊的なメソッドですが、filter が新しい配列を作ったあとなので、ここでは元のデータに影響しません。filter を先に置くのは、見た目の都合ではなくこの理由からです。
全体の流れ
3 つをつないで、失敗の道も用意すると次の形になります。
const status = document.querySelector("#status");
async function loadWorks() {
status.textContent = "読み込み中";
try {
const response = await fetch("https://yumesaku.tech/course-api/works.json?delay=800");
if (!response.ok) {
throw new Error("作品を読み込めませんでした (" + response.status + ")");
}
const data = await response.json();
const selected = selectWorks(data.works);
renderWorks(selected);
status.textContent = selected.length + " 件の作品を読み込みました";
} catch (error) {
renderWorks([]);
status.textContent = error.message;
}
}
loadWorks();status の 1 行が、画面の状態をそのまま表しています。読み込み中なのか、何件出ているのか、失敗したのか。利用者が知りたいことは、この 3 つだけです。
件数は
data.countではなく、実際に描いたselected.lengthから作ります。絞り込んだあとなので、2 つの数はずれます。画面に出す数字は、画面に出ているものから数えてください。
もう一度読み込めるようにする
失敗したまま何もできない画面は不親切です。やり直すボタンを置いて、押されたら同じ関数をもう一度呼びます。ここまで loadWorks を 1 本の関数にしておいたので、足すのは 3 行だけです。
const reloadButton = document.querySelector("#reload");
reloadButton.addEventListener("click", () => {
loadWorks();
});loadWorks の中で毎回「読み込み中」から始まり、renderWorks が一覧を消してから描き直すので、2 回押してもカードが二重にならないことを確かめてください。ここが二重になるなら、消す処理がどこかで抜けています。
押している間にボタンを押せなくする、という配慮もできます。第8章で覚えた考えかたと同じです。
async function loadWorks() {
reloadButton.disabled = true;
status.textContent = "読み込み中";
try {
// ... 通信と描画 ...
} catch (error) {
// ... 失敗の表示 ...
} finally {
reloadButton.disabled = false;
}
}finally に置くのが要点です。成功しても失敗しても、ボタンは必ず押せる状態に戻さなければなりません。第6章で finally を「どちらの道でも通る場所」と説明したのは、こういう後始末のためでした。
動いていることをどう確かめるか
書き終えたら、URL の後ろを変えて 3 通り試してください。練習用の口は、そのために挙動を変えられるようにしてあります。
| 付ける指定 | 確かめられること |
|---|---|
?delay=800 | 読み込み中が見えて、そのあと消えるか |
?status=500 | 失敗の文が出て、カードが空になるか |
?empty=1 | 0 件のときに画面が壊れないか |
?empty=1 は作品が 0 件で返ってきます。このとき renderWorks([]) が呼ばれ、一覧は空になります。空でも壊れないかは、実際に試さないと分かりません。「0 件です」と出すところまで作れると、より丁寧な画面になります。
通信を使う画面は、うまくいったときだけ試しても完成しません。遅いとき、失敗したとき、中身が空のとき。この 3 つを自分で起こして確かめるところまでが作業です。
よくある間違い
手で書いた配列を消し忘れる
// 直したい書きかた。取ってきたデータを描いたあと、古い配列で上書きしている
const works = [{ title: "プロフィールサイト", views: 120 }];
loadWorks();
renderWorks(works);
// 出どころをひとつにする。手書きの配列はもう要らない
loadWorks();選ぶ処理を描画の中に混ぜる
// 直したい書きかた。renderWorks が絞り込みまで知ってしまう
function renderWorks(works) {
works.forEach((work) => {
if (!work.published) return;
list.append(createCard(work));
});
}
// 選んでから渡す。描く側は渡されたものを全部描く
renderWorks(selectWorks(data.works));失敗したときにカードを消し忘れる
// 直したい書きかた。前のカードが残ったままエラー文が出る
catch (error) {
status.textContent = error.message;
}
// 画面を失敗したなりに整える
catch (error) {
renderWorks([]);
status.textContent = error.message;
}課題
- fetch より先に #status へ「読み込み中」を入れる
- selectWorks は published が true のものだけを残し、views の多い順に並べて返す
- createWorkCard は views が 100 以上の作品に featured クラスを付ける
- #status に、実際に描いた件数を出す
- response.ok が false なら throw し、catch で一覧を空にしてエラー文を出す