Vue komponent renderad av v-for uppdateras inte när array gör det

Permalänk
Medlem

Vue komponent renderad av v-for uppdateras inte när array gör det

Jag försöker rendera ett table med hjälp av v-for="(item) in arrayName". Min array hämtar data från en databas med asynkrona anrop och det är nog här det blir problem. Jag tänker mig att listan är tom när sidan först renderas, därav inga items i mitt table. Men som jag förstår det ska Vue rendera om när min array uppdateras med arrayName.push(item). Om jag ändrar något i min HTML och sparar renderas plötsligt allt korrekt.

Någon som har en aning om vad som blir fel? Kan dela mer kod om någon är nyfiken men jag tänker mig att problemet främst ligger i hur vue hanterar uppdateringar, koden tycks ju fungera när det väl laddas om

Visa signatur

Case: Lian Li PC-O11 Dynamic - Motherboard: MSI MAG X570 TOMAHAWK WIFI - CPU: AMD Ryzen 5 3600 - GPU: Gainward GeForce RTX 3080 Phantom 10G - RAM: G.Skill 32GB DDR4 3600MHz CL18 Trident Z Neo - PSU: Corsair RM750X - SSD: Kingston A2000 1TB

Permalänk
Medlem

Låter som du kanske deklarerar data fel?

Se till att data faktiskt returnerar korrekt enligt:

data() { return { arrayName: [] } }

ändras datan i arrayName nu så kommer det garanterat vara reaktivt.

Visa signatur

AW3423DW QD-OLED - Ryzen 5800x - MSI Gaming Trio X 3090 - 64GB 3600@cl16 - Samsung 980 Pro 2TB/WD Black SN850 2TB

Permalänk
Medlem

Hej! Kan du prova att lägga till :key på varje element du lägger ut? Du kan läsa mer om :key i dokumentation: https://v2.vuejs.org/v2/guide/list.html Det finns en del bra att lämna till om reaktivitet i Vue, skulle rekommendera läsning här: https://v2.vuejs.org/v2/guide/reactivity.html#For-Arrays (obs v2)

Kan du inspektera att verkligen data ändras i komponenten? Är du säker på att det enbart är rendering på sidan som är problemet?

Permalänk
Medlem
Skrivet av celoz:

Låter som du kanske deklarerar data fel?

ändras datan i arrayName nu så kommer det garanterat vara reaktivt.

Skrivet av Johan_S:

Hej! Kan du prova att lägga till :key på varje element du lägger ut?

Kan du inspektera att verkligen data ändras i komponenten? Är du säker på att det enbart är rendering på sidan som är problemet?

<template> ... <tr v-for="(item, index) in purchases" :key="index" :index="index"> <td>{{index + 1 + '.'}}</td> <td>{{item.entries[0].payee}}</td> <td><img src="../assets/städning.png" alt="Generisk Bild"></td> <td>{{'1'}}</td> <td>{{item.entries[0].quant}}</td> <td>{{item.entries[0].quant}}</td> <td className="green">{{item.state}}</td> <td className="red">Ladda ner faktura</td> </tr> ... </template> <script> import { asyncFunc1, asyncsFunc2 } from ... export default { data () { const arrayName = [] asyncFunc1() .then(res => { Object.keys(res).forEach(function (key) { asyncFunc2()(res[key]) .then(res => { arrayName.push(res) }) }) console.log(arrayName) }) return { arrayName: arrayName } } } </script>

Här är relevant kod. Jag är osäker på vad :key egentligen gör i sammanhanget. Jag kan se att min array fylls med datan men mitt table uppdateras inte om jag inte ändrar något i HTML.

Visa signatur

Case: Lian Li PC-O11 Dynamic - Motherboard: MSI MAG X570 TOMAHAWK WIFI - CPU: AMD Ryzen 5 3600 - GPU: Gainward GeForce RTX 3080 Phantom 10G - RAM: G.Skill 32GB DDR4 3600MHz CL18 Trident Z Neo - PSU: Corsair RM750X - SSD: Kingston A2000 1TB

Permalänk
Medlem

Ser ut som att data inte är korret, nu är jag van vid v2 och inte 3 så hoppas inte jag leder dig fel. Men här är ett exempel på hur data bör se ut:

Data ska enligt dokumentation returnera ett object. Din funktion definerar du som en method, som du tex kan ropa på i mounted-hook. Ang :key så hjälper det Vue lista ut vad som behöver renderas om, har du unika id på din data är det ännu bättre att använda det som key istället för index i arrayen.

export default { data () { return { arrayName: [], }; }, mounted() { // When this component is mounted, fetch data console.log('Component mounted!'); this.fetchMyData(); }, methods: { // Method to fetch last data and update arrayName async fetchMyData() { console.log('fetchMyData start!'); asyncFunc1() .then(res => { this.arrayName = res; console.log(this.arrayName) }); }, }, } </script>

EDIT: Om du inte redan har plugin i Chrome för att inspektera rekomenderar jag https://chrome.google.com/webstore/detail/vuejs-devtools/nhdo...
Då hade du säkert sett att data inte ser korrekt ut. Och en bra syntax hade get dig fel att data inte är korrekt formaterad, tex Vetur plugin i vscode.

Tips Chrome
Permalänk
Medlem
Skrivet av Johan_S:

Ser ut som att data inte är korret, nu är jag van vid v2 och inte 3 så hoppas inte jag leder dig fel. Men här är ett exempel på hur data bör se ut:

export default { data () { return { arrayName: [], }; }, mounted() { // When this component is mounted, fetch data console.log('Component mounted!'); this.fetchMyData(); }, methods: { // Method to fetch last data and update arrayName async fetchMyData() { console.log('fetchMyData start!'); asyncFunc1() .then(res => { this.arrayName = res; console.log(this.arrayName) }); }, }, } </script>

Jag uppskattar verkligen att du svarar, men tyvärr blev det ingen skillnad med din implementation Gjorde ett försök med en v-if på mitt table som är beroende av en bool som uppdateras när min array uppdateras, men det gjorde heller ingen skillnad.

Visa signatur

Case: Lian Li PC-O11 Dynamic - Motherboard: MSI MAG X570 TOMAHAWK WIFI - CPU: AMD Ryzen 5 3600 - GPU: Gainward GeForce RTX 3080 Phantom 10G - RAM: G.Skill 32GB DDR4 3600MHz CL18 Trident Z Neo - PSU: Corsair RM750X - SSD: Kingston A2000 1TB

Permalänk
Medlem
Skrivet av Murvar:

<template> ... <tr v-for="(item, index) in purchases" :key="index" :index="index"> <td>{{index + 1 + '.'}}</td> <td>{{item.entries[0].payee}}</td> <td><img src="../assets/städning.png" alt="Generisk Bild"></td> <td>{{'1'}}</td> <td>{{item.entries[0].quant}}</td> <td>{{item.entries[0].quant}}</td> <td className="green">{{item.state}}</td> <td className="red">Ladda ner faktura</td> </tr> ... </template> <script> import { asyncFunc1, asyncsFunc2 } from ... export default { data () { const arrayName = [] asyncFunc1() .then(res => { Object.keys(res).forEach(function (key) { asyncFunc2()(res[key]) .then(res => { arrayName.push(res) }) }) console.log(arrayName) }) return { arrayName: arrayName } } } </script>

Här är relevant kod. Jag är osäker på vad :key egentligen gör i sammanhanget. Jag kan se att min array fylls med datan men mitt table uppdateras inte om jag inte ändrar något i HTML.

Data ska returera ett object med ditt state, du ska inte göra direkta anrop i data.
Du vill definera dina metoder i methods och anropa dem i dina life-cycle methods, t.ex. created.

Key är ett unikt ID som används av Vue i sin virtual DOM för att veta vad exakt som behöver renderas om. Vue kan räkna ut detta själv, men det tar mer prestanda om du jobbar med stora datamängder. Så se det som ett index som gör att Vue endast behöver rendera om objektet på plats 251 i din array istället för att räkna ut det själv först.

Här är ett exempel på ett async anrop som hämtar todos via ett api och sätter state i data.

<template> <div id="app"> <ul v-if="todos.length"> <li v-for="todo in todos" :key="todo.id"> {{ todo.title }} </li> </ul> </div> </template> <script> export default { name: "App", data() { return { todos: [], }; }, async created() { await this.fetchTodos(); }, methods: { fetchTodos: async function (todo) { const res = await fetch("https://jsonplaceholder.typicode.com/todos"); const data = await res.json(); this.todos = data; }, }, }; </script>

Permalänk
Medlem
Skrivet av zaibuf:

Data ska returera ett object med ditt state, du ska inte göra direkta anrop i data.
Du vill definera dina metoder i methods och anropa dem i dina life-cycle methods, t.ex. created.

Key är ett unikt ID som används av Vue i sin virtual DOM för att veta vad exakt som behöver renderas om. Vue kan räkna ut detta själv, men det tar mer prestanda om du jobbar med stora datamängder. Så se det som ett index som gör att Vue endast behöver rendera om objektet på plats 251 i din array istället för att räkna ut det själv först.

Här är ett exempel på ett async anrop som hämtar todos via ett api och sätter state i data.

...

Tyvärr funkar inte det här heller. Fortsatt samma beteende som i min originalkod. Jag har åtminstone lärt mig mer om hur Vue fungerar nu

Visa signatur

Case: Lian Li PC-O11 Dynamic - Motherboard: MSI MAG X570 TOMAHAWK WIFI - CPU: AMD Ryzen 5 3600 - GPU: Gainward GeForce RTX 3080 Phantom 10G - RAM: G.Skill 32GB DDR4 3600MHz CL18 Trident Z Neo - PSU: Corsair RM750X - SSD: Kingston A2000 1TB

Permalänk
Medlem
Skrivet av Murvar:

Tyvärr funkar inte det här heller. Fortsatt samma beteende som i min originalkod. Jag har åtminstone lärt mig mer om hur Vue fungerar nu

Det jag postade fungerar om du kör det med en JsFiddle. Så problemet är snarare i någon av metoderna du importerar och inte visar. Magkänslan säger att något körs i async men inte inväntas, eller att state inte uppdateras korrekt. Hur ser koden ut efter att du ändrat till ovan nämna implementation?

Har du debuggat koden med debuggern i VSCode?

Du kan också installera VueJs extension till Google Chrome om du inte redan har den. Där kan du gå in i en komponent och kika på state.
https://chrome.google.com/webstore/detail/vuejs-devtools/nhdo...

Edit:
Kan tillägga att metoden du använder .forEach inte stödjer async.
https://gist.github.com/joeytwiddle/37d2085425c049629b80956d3...

Svårt utan att se exakt vad koden i metoderna du anropar gör, men det ser ut som att du göra asynkrona anrop i en loop, vilket blir o(n) och kan sänka prestandan rätt rejält beroende på mängden anrop du gör.
Du bör också få enormt många re-renders om du uppdaterar state i en loop. Jag rekommenderar att du hämtar ut allt och sen sätter hela arrayn en gång för att trigga en re-render.

Du skulle kunna börja med att debugga första delen av anropet och sedan applicera nästa.
Kika om du får en korrekt console log från asyncFunc1.

import { asyncFunc1, asyncsFunc2 } from ... export default { data() { return { arrayName: [], }; }, async created() { const res = await asyncFunc1(); console.log(res); } }

Grammatik
Permalänk
Medlem

Den här koden fick allt att fungera

export default { data () { return { arrayName: [] } }, mounted: function () { asyncFunc(x, y) .then(res => { this.arrayName = res }) } }

Visa signatur

Case: Lian Li PC-O11 Dynamic - Motherboard: MSI MAG X570 TOMAHAWK WIFI - CPU: AMD Ryzen 5 3600 - GPU: Gainward GeForce RTX 3080 Phantom 10G - RAM: G.Skill 32GB DDR4 3600MHz CL18 Trident Z Neo - PSU: Corsair RM750X - SSD: Kingston A2000 1TB