【问题标题】:v-for list doesn't update when new data is fetched asynchronously异步获取新数据时 v-for 列表不更新
【发布时间】:2021-10-20 11:48:49
【问题描述】:

我有一个使用 Vue.js 和 SignalR 创建的页面,用于实时更新交易。

在初始页面加载时,我的 Vue 数据被分配从服务器获取的值,然后我循环遍历这些值以创建一个列表。

但是,当接收到来自 SignalR 的更新时,使用 v-for 创建的列表不会更新为新数据(但 console.log 会显示更新的数据)。

当我刷新页面时,我会看到新数据与新数据一起呈现的列表。

这里是上下文的一些代码:

HTML:

<div class="accordion accordion-wrapper" id="deposits-accordion">
                                        <div v-for="(deposit, index) in account.deposits" class="card plain accordion-item" :key=deposit.id>
                                            <div class="card-header pb-0" :id="deposit.tokenName + index">
                                            <button class="accordion-button d-flex justify-content-between row" data-bs-toggle="collapse" :data-bs-target="'#deposit' + index" aria-expanded="false" aria-controls="collapseOne"> 
                                                <p class="col-4">
                                                    {{ deposit.tokenSymbol }} 
                                                </p>
                                                <p class="col-4 text-center">
                                                    {{ deposit.amount / 100 }} 
                                                </p>

                                                <p class="col-4 px-0 text-end">
                                                    
                                                    <span v-if="deposit.confirmDate" class="badge rounded-pill bg-info">Confirmed</span>
                                                    <span v-else class="badge rounded-pill bg-secondary">Pending</span>
                                                </p>
                                                
                                                
                                            </button>
                                            </div>
                                            
                                            <div :id="'deposit' + index" class="accordion-collapse collapse" :aria-labelledby="deposit.tokenName + index" data-bs-parent="#deposits-accordion">
                                            <div class="card-body mb-10">
                                                <p class="mb-1"><strong>ID:</strong> {{ deposit.id}}</p>
                                                <p class="mb-1"><strong>Deposit Address:</strong> {{ deposit.depositAddress}}</p>
                                                <p class="mb-1"><strong>txId</strong> {{ deposit.txId}}</p>
                                                <p class="mb-1"><strong>Time Stamp:</strong> {{ deposit.timestamp}}</p>
                                                <p class="mb-1"><strong>Amount:</strong> {{ deposit.amount / 100}} {{ deposit.tokenSymbol}}</p>
                                                <p class="mb-1"><strong>Token Name:</strong> {{ deposit.tokenName}}</p>
                                                <p class="mb-1"><strong>Confirm Date:</strong> {{ deposit.confirmDate}}</p>
                                                
                                            </div>
                                            
                                            </div>
                                            
                                        </div>
                                    </div>

JS:

<script type="module" async>
            import { server } from "./assets/js/config.js";
            import { getProject } from "./assets/js/saleproject.js";
            import { getAccountById } from "./assets/js/account.js";
            import { createApp } from 'https://unpkg.com/vue@3.2.4/dist/vue.esm-browser.js'
            //Get accountId from querystring
            let accountId = getQueryStringByParameter("accountId");

            //Load initial data using API
            var accountData = await getAccountById(accountId);

            //First setup SignalR connection
            var connection = new signalR.HubConnectionBuilder()
                .withUrl(server + "/statusHub")
                .withAutomaticReconnect()
                .build();

            connection
                .start()
                .then(function () {
                    connection
                        .invoke("AddToGroup", accountId)
                        .catch(function (err) {
                            return console.error(err.toString());
                        });
                })
                .catch(function (err) {
                    return console.error(err.toString());
                });

            connection.on(
                "UpdateAccount",
                async function (currentAccountId, reason) {
                    accountData = await getAccountById(accountId);
                    console.log(typeof accountData);
                    console.log(typeof this.account);
                    console.log('Updated data');
                    console.table(accountData.deposits);
                    this.account = accountData;
                    console.log('Updated data VUE');
                    console.table(this.account.deposits);
                    console.log("Update from signalr: " + reason + ' ' + currentAccountId);
                }
            );

            connection.onclose(async () => {
                await start();
            });


            //Project code
            if (accountData.lastOrder.saleProjectCode != null) {
                var projectData = await getProject(accountData.lastOrder.saleProjectCode)
                console.log('Sale Project')
                console.table(accountData.lastOrder)
            }

            //Calculate total
            let totalDue = (accountData.lastOrder.amount - accountData.lastOrder.amountFilled) * projectData.salePrice;

            function getQueryStringByParameter(name) {
                name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
                var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
                    results = regex.exec(location.search);
                return results == null
                    ? ""
                    : decodeURIComponent(results[1].replace(/\+/g, " "));
            }

            //Vue

            createApp({
                data: () => ({
                    account: accountData,
                    walletValid: accountData.account.isValidWithdrawAddress,
                    depositAddress: server + "/qr/" + accountData.account.depositAddress,
                    clipboardDepositAddress: accountData.account.depositAddress,
                    salePrice: totalDue,
                }),
                methods: {
                    copyDepositAddress() {
                        navigator.clipboard.writeText(this.clipboardDepositAddress)
                    }
                }
            }).mount("#js-account");

        </script> 

【问题讨论】:

    标签: javascript vue.js signalr vuejs3


    【解决方案1】:

    您正在尝试使用创建时可能不存在的属性更新对象,由于 Vue 的工作方式,这些属性不会响应。

    见:https://vuejs.org/v2/guide/reactivity.html#For-Objects

    还有

    this.account = accountData;
    

    this 可能无法在函数调用中工作,因为this 是上下文相关的。

    【讨论】:

    • 好的,谢谢 - 所以看起来如果我降级到 Vue 2 并使用 $set 我可以让它变得被动?
    • 不,上面提到的反应性问题不适用于您正在使用的 Vue 3。但是this.account = accountData 可能是错误的,因为this 内部的UpdateAccount 处理程序不太可能是Vue 组件
    猜你喜欢
    • 2018-05-09
    • 2017-03-05
    • 2016-11-12
    • 1970-01-01
    • 1970-01-01
    • 2021-06-29
    • 1970-01-01
    • 2019-10-14
    • 2021-12-16
    相关资源
    最近更新 更多