我有一個管理一些陣列的類,它們填充了我從我使用的 API 中獲取的資料。這些串列按狀態代表客戶,根據他們的狀態,我將這些客戶存盤在相應的串列中。出于隱私原因,我無法與您分享整個代碼,但我可以提取一些內容來幫助您理解我的問題。
讓我們假設以下情況,我像這樣初始化所說的陣列:
this.waitingClientsList = [];
this.usersAttendedList = [];
this.absentClientsList = [];
this.suspendedClientsList = [];
this.announcedClientsList = [];
this.clientsBatch = [];
每個串列都將從空開始。
為了避免重復太多代碼,我用這樣的字典來管理它們:
this.listsByState = {
"waiting": this.waitingClientsList,
"suspended": this.suspendedClientsList,
"absent": this.absentClientsList,
"inattention": this.usersAttendedList,
"invideocall": this.usersAttendedList,
"announced": this.announcedClientsList,
"vdconnectingerror": this.usersAttendedList,
"videocallended": this.usersAttendedList,
"vdmissedcall": this.usersAttendedList
}
為了更新他們的內容,我有一個函式來檢查一個與分頁一起使用的 API 方法,檢索資料并將其存盤在各自的串列中,如下所示(這是一個示例):
private GetWaitingClients(state, nextPage, id, pageSize?, pageNumber?) {
this._requestService.getWaitingClients(state, id, pageSize, pageNumber).then(async (response: any[]) => {
// Getting the list by state
let clientList = this.listsByState[state];
// if we are changing the page, we should empty the respective list
if (nextPage) {
clientList = [];
}
response.map(item => {
// If the client doesn't exist, it pushes it to the list
// otherwise I manipulate the client
if (clientList.some(obj => obj.virtualSpaceId == item.virtualSpaceId)) {
// I do something here if the client exists
} else {
// If not, I push it to the list
clientList.push(item);
}
});
[...]
// More stuff that I do
}).catch(error => {
// Here I print the error in case there was a problem with the API request
});
}
我用這行代碼檢索每個串列let clientList = this.listsByState[state];,這是我發現避免執行 switch/case 陳述句或多個 if/else 陳述句的方法。到目前為止,這作業正常。如果資料庫中有一個新條目,區域變數clientList和它們參考的陣列都會相應地更新,那里沒有問題。
我在 API 中構建了一種方法,即第一次加載頁面時,它將回傳帶有 5 個結果的第一頁。如果我更改前端的頁面,該函式就會啟動并應檢索接下來的 5 個結果,依此類推。
問題是,當我更改頁面時,clientList如果我更改其內容,變數確實會更新,但原始參考的陣列不會更新,這讓我很煩惱。據我了解,在執行此任務時,let clientList = this.listsByState[state];我假設它clientList指向記憶體中對應串列的同一物件,但這里沒有發生這種情況,所以我不知道我的問題出在哪里。我也嘗試clientList在執行map操作之前清空變數,但它什么也沒做,原始陣列保持不變。
The only way I can manage to change the referenced array content is by doing a direct assignment like this, for example: this.waitingClientsList = clientList, but this invalidates my previous code and that lefts me with no choice but to do a big and ugly switch/case statement or multiple if/else statements which I don't want to do. I'm trying to keep my code as clean as possible.
Any suggestions? Thanks in advance!
uj5u.com熱心網友回復:
// Getting the list by state
let clientList = this.listsByState[state];
// if we are changing the page, we should empty the respective list
if (nextPage) {
clientList = [];
}
您是否希望這行代碼也重置 this.listsByStatep[state] 的陣列?它不會這樣做,因為您已將新陣列分配給 clientList,因此參考不相同(您可以通過在console.log(clientList === this.listsByStatep[state])分配 [] 之前和之后執行此操作來檢查這一點)。要執行您正在尋找的操作,請將其更改為:
// Getting the list by state
let clientList = this.listsByState[state];
// if we are changing the page, we should empty the respective list
if (nextPage) {
clientList.length = 0;
}
這不會破壞參考并清空陣列。
uj5u.com熱心網友回復:
這是一個經典的 JS 錯誤:
- 將物件的參考分配給一個新變數(通常是為了縮短代碼)
var short = myObject.some.long.path.or[dynamicKey] - 進行深度更改 => 正確修改了原始物件
short.subProperty = 2; myObject.some.long.path.or[dynamicKey].subProperty === 2; - 重新分配變數并期望相應地修改原始物件 => 失望 :-(
short = null; myObject.some.long.path.or[dynamicKey].subProperty === 2;
(在示例中我使用了一個物件,但對于陣列也是如此)
在您的情況下,由于您的test動態密鑰始終在范圍內,因此您可以在想要訪問相應串列時繼續使用它:this.listsByState[state] = [];
是的,它可能看起來多余/可讀性較差,但您現在至少有一個作業代碼。
現在要正確使用您的新clientList變數并繼續修改原始串列,如上所示以及 MathewBerg 的回答所暗示的,只需確保始終使用使物件就地變異的深層屬性或函式:
clientList.length = 0; // works
clientList.splice(0, clientList.length); // to empty
clientList.push("itemAtTheEnd"); // works
clientList.unshift("itemAtTheStart"); // works
clientList.splice(2, 0, "insertedItem"); // to insert after the 2nd item
clientList.pop();
clientList.shift();
clientList.splice(3, 1); // to remove the 3rd item
通過防止重新分配,您可以輕松地在代碼中強制執行此規則:
// Initialize a const variable to forbid re-assignment
const clientList = this.listsByState[state];
uj5u.com熱心網友回復:
首先感謝@ghybs和@Mathew Breg的建議。
首先,我洗掉了這個clientList = []任務,而是使用clientList.length = 0了你們倆所指出的完美的作業方式。我發現了另一個 SO 問題,它指出clientList = [],實際上,如果您沒有對原始陣列的參考,則是清空陣列的最快方法,否則原始陣列將保持不變。那是我的第一個錯誤。
第二個錯誤是(這也是我之前沒有提到的并且需要返工)我目前有subscription一個服務來控制我沒有正確處理的頁面可見性。每次我的頁面獲得焦點時,原始陣列都將完全填充,并且顯示為未更改。一旦我評論了那段代碼,并在clientList.length = 0這里和那里進行了一些更正,一切都開始完美無缺。
我添加到代碼中的另一件事是幫助我重繪 表視圖(我忘記了=> 顯示結果,我目前正在使用MatTable和MatPaginator用于來自Angular Material的資料分頁)是renderRows()來自MatTable我用來在更改頁面索引后在頁面上顯示資料。
我很樂意將這兩條評論標記為我的問題的答案,因為盡管這行簡單的代碼clientList.length = 0是操作原始陣列參考的正確方法,但在進行了更多測驗和除錯后,問題出在我的代碼中的其他地方。現在,我會標記@Mathew Breg的答案,但我想讓你們知道你們倆都是正確的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/385193.html
