Maison > Questions et réponses > le corps du texte
J'ai un effet vuejs étrange, lorsque j'ajoute de nouvelles données d'objet, v-for restitue tous les objets, même s'ils ont déjà été rendus.
J'implémente le défilement infini comme Facebook.
Pour expliquer ce code, je récupère de nouvelles données de Firebase, puis je les transmets dans un objet de données lorsqu'elles atteignent le bas de l'écran
var vueApp = new Vue({ el: '#root', data: { postList: [], isOkaytoLoad: false, isRoomPostEmpty: false, }, mounted: function() { // Everytime user scroll, call handleScroll() method window.addEventLis tener('scroll', this.handleScroll); }, methods: { handleScroll: function() { var d = document.documentElement; var offset = d.scrollTop + window.innerHeight; var height = d.offsetHeight - 200; // If the user is near the bottom and it's okay to load new data, get new data from firebase if (this.isOkaytoLoad && offset >= height) { this.isOkaytoLoad = false; (async()=>{ const lastPost = this.postList[this.postList.length - 1]; const room_id = PARAMETERS.get('room'); const q = query(collection(db, 'posts'), where('room', '==', room_id), orderBy("time", "desc"), limit(5), startAfter(lastPost)); const roomSnapshot = await getDocs(q); roomSnapshot.forEach((doc) => { const postID = doc.id; (async()=>{ // Put the new data at the postList object this.postList = [...this.postList, doc]; const q = query(collection(db, 'comments'), where('post_id', '==', postID)); const commentSnapshot = await getDocs(q); doc['commentCount'] = commentSnapshot.size; //this.postList.push(doc); console.log(this.postList); setTimeout(()=>{ this.isOkaytoLoad = true }, 1000); })(); }); })(); } } } })
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div v-if="postList.length > 0" class="card-containers"> <!-- I have a component `Postcard` in my js file and it works well --> <Postcard v-for="post in postList" :key="post.id" :post-id="post.id" :owner-name="post.data().owner_displayName" :owner-uid="post.data().owner_id" :post-type="post.data().post_type" :image-url="post.data().image_url" :post-content="truncateString(linkify(post.data().post_content))" :room="post.data().room" :time="post.data().time.toDate()" :likers="post.data().likers" :comment-count="post.commentCount" :file-url="post.data().file_url" :file-name="post.data().file_name" :downloads="post.data().downloads"> </Postcard> </div>
Regardez cet enregistrement d'écran, souris focalisée, c'est tellement lent, je ne peux même pas cliquer sur les boutons pendant que vuejs ajoute et charge de nouvelles données
C'est le code que j'utilise
Je soupçonne qu'à chaque fois que de nouvelles données sont ajoutées, VueJS restitue toutes les données, provoquant cet effet. Comment forcer vueJS à ne pas restituer les données déjà restituées à l'écran ?
P粉5671123912023-12-29 16:34:20
Vous avez deux IIFE asynchrones inutiles ; le second dans forEach
est particulièrement problématique car le code asynchrone qu'il contient sera exécuté simultanément à chaque itération de boucle, ce qui a les effets suivants :
getDocs()
se déclenchera immédiatement à chaque itération de boucle, envoyant éventuellement du spam au serveur (en supposant qu'il s'agit d'une requête réseau). Est-ce votre intention ? Il semble que vous ne puissiez recevoir qu'un maximum de 5 nouveaux messages, donc c'est probablement bien. N’utilisez pas var
;使用 const
或 let
代替。几乎没有充分的理由再使用 var
non plus, laissez-le mourir.
Je ne peux pas dire que cela améliorera significativement vos performances, mais je recommande les changements suivants (non testés) :
async handleScroll() { const d = document.documentElement; const offset = d.scrollTop + window.innerHeight; const height = d.offsetHeight - 200; // If the user is near the bottom and it's okay to load new data, get new data from firebase if (this.isOkaytoLoad && offset >= height) { // Prevent loading while we load more posts this.isOkaytoLoad = false; try { // Get new posts const lastPost = this.postList[this.postList.length - 1]; const room_id = PARAMETERS.get('room'); const q = query(collection(db, 'posts'), where('room', '==', room_id), orderBy("time", "desc"), limit(5), startAfter(lastPost)); const roomSnapshot = await getDocs(q); // Fetch comments of each post. Do this all at once for each post. // TODO: This can probably be optimized into a single query // for all the posts, instead of one query per post. await Promise.all(roomSnapshot.docs.map(async doc => { const postID = doc.id; const q = query(collection(db, 'comments'), where('post_id', '==', postID)); const commentSnapshot = await getDocs(q); doc.commentCount = commentSnapshot.size; })); // Append the new posts to the list this.postList.push(...roomSnapshot.docs); } catch (ex) { // TODO: Handle error } finally { // Wait a bit to re-enable loading setTimeout(() => { this.isOkaytoLoad = true }, 1000); } } }
Exécution dans le modèle :post-content="truncateString(linkify(post.data().post_content))"
意味着 linkify
将在每次重新渲染期间执行。我怀疑 linkify
Peut-être lente pour les longues listes ? Peut-il être pré-calculé pour chaque poste à l’avance ?
Lorsque le composant est installé, vous enregistrez un écouteur d'événement de défilement de fenêtre. Si le composant est détruit, vous devez désenregistrer l'écouteur d'événements, sinon il se déclenchera toujours à chaque défilement de la fenêtre. Cela ne pose peut-être pas de problème dans votre cas, mais pour les composants réutilisables, c'est nécessaire.