無限スクロールを作っていますが、ajaxで取得したデータを元に要素を生成したいのですが、毎回1つか2つ生成されず抜けがあります。データは全てサーバーから取得できているためjs内に問題があります。
追記
TypeError: Cannot read properties of undefined (reading 'user_id')とエラーを吐きました。「 this.AjaxCommentUser(data.comments[i].user_id)」が問題の箇所ですが、data.commentsの各オブジェクト内にuser_idはあるのでなぜこのようなエラーを返すのかわかりません
該当のソースコード
index.blade.php
methods: { AjaxAddContent() { if (!this.itemLoading) { //読み込み中は読み込めないようにする this.itemLoading = true // 追加コンテンツ fetch('/ajax/getSidebarComment', { method: 'POST', body: new URLSearchParams({ count: this.page }), headers: { 'X-CSRF-TOKEN': gid("jsHandOvers").dataset.csrf }, }).then(res => { return res.json(); }).then(data => { // console.log(data.comments.length) let AddContent = ""; for (let i = 0; data.comments; i++) { this.AjaxCommentUser(data.comments[i].user_id) .then(user => { this.AjaxCommentArticle(data.comments[i].article_id) .then(article => { ↓ここで要素を作るがなぜか抜けがある AddContent += `<div class="streamTile"><div><a href="/articles/${data.comments[i].article_id}?id=${data.comments[i].id}"></a><div class="userInfo"><a href="/users/${user.userID}"><div class="userIcon"><img src="/storage/${user.icon || 'icon/initial.jpeg'}" class="icon"></div><div><div class="userName _ellipsised">${user.name || '氏名'}</div><div class="userID">@${user.userID}</div></div></a><div class="commentDate">${data.comments[i].updated_at}</div></div><div class="commentArea"><div class="comment _ellipsised">${data.comments[i].body || ''}</div></div><div class="titleArea"><div class="title _ellipsised">${article.title}</div></div></div></div><div class="tileSeparator"></div>`; if (data.comments.length - 1 === i) { $('#timelineContainer').append(AddContent); this.page += data.comments.length } }).catch(err => {}); }).catch(err => {}); } }).catch(err => { // console.log(err.response) this.itemLoading = false }).finally(hoge => { this.itemLoading = false }); } }, async AjaxCommentUser(user_id) { let res = await fetch(`/ajax/users/${user_id}`, { method: 'POST', headers: { 'X-CSRF-TOKEN': gid("jsHandOvers").dataset.csrf }, }); let data = await res.json(); return data.user; }, async AjaxCommentArticle(article_id) { let res = await fetch(`/ajax/articles/${article_id}`, { method: 'POST', headers: { 'X-CSRF-TOKEN': gid("jsHandOvers").dataset.csrf }, }); let data = await res.json(); return data.article; }, } }).mount("#timelineContainer");
試したこと
「ajax 全て表示」等で検索
補足情報(FW/ツールのバージョンなど)
PHP 8.1.1
Laravel 8.79.0
await が抜けてるところがあるのでは?
catch(err => {}) でエラーが握りつぶされてるかも?
ちなみにfetchはXMLHttpRequestではないのでajaxと呼ぶべきかどうかは判断が分かれます
SurferOnWwwさん
どこかが非同期処理になってしまっているようですね
hoshi-takanoriさん
その中でconsole.log(err)したら「TypeError: Cannot read properties of undefined (reading 'user_id')」と返ってきました
yambejpさん
ありがとうございます。
int32_t さんの回答にある通り、ループの終了条件がおかしいために無限ループになり、data.comments の個数よりも i が大きくなると data.comments[i] が undefined なので user_id にアクセスできなくてエラーになってるのでしょうね。が、表示漏れの原因はそれではなく、非同期で結果が返ってくる順番の問題だと思います。
ちなみに、user や article を一つ一つ分けて取得するのは効率が悪いので、API を修正できるなら getSidebarComment でまとめて返すようにした方がいい気がします。
hoshi-takanori
ありがとうございます。getSidebarCommentで全て取得したら思い通りの処理を実現できました
まだ回答がついていません
会員登録して回答してみよう