iT邦幫忙

2021 iThome 鐵人賽

DAY 14
0
Modern Web

[ 重構倒數30天,你的網站不Vue白不Vue ] 系列 第 14 篇

[重構倒數第17天] - 重組資料格式減少不必要的迴圈執行

  • 分享至 

  • xImage
  •  

前言

該系列是為了讓看過Vue官方文件或學過Vue但是卻不知道怎麼下手去重構現在有的網站而去規畫的系列文章,在這邊整理了許多我自己使用Vue重構很多網站的經驗分享給讀者們。

我們在網頁上很常會需要顯示例如商品的 list 或是有列表的 UI,而我們拿回來的資料很常會屬於 array 裡面包了很多 Object 的 JSON 格式,然後會透過 v-for把 list 給 render 出來。

[
	{
    createdAt: "2021-08-17T07:11:29.033Z",
    name: "Sonja Grady",
    avatar: "https://cdn.fakercloud.com/avatars/popey_128.jpg",
    userId: "399",
    username: "Clair.Langosh30",
    id: "1"
  },
  {
    createdAt: "2021-08-17T06:19:11.959Z",
    name: "Megan Mertz",
    avatar: "https://cdn.fakercloud.com/avatars/beshur_128.jpg",
    userId: "067",
    username: "Arlene_West",
    id: "2"
  },
  {
  	createdAt: "2021-08-16T21:28:36.284Z",
    name: "Lonnie Luettgen",
    avatar: "https://cdn.fakercloud.com/avatars/jydesign_128.jpg",
    userId: "827",
    username: "Gerard_Rodriguez",
    id: "3"
  },
  ...
]

今天我們有 item 這個 API,我在 item 這個 API 把資料給取回來,然後我需要透過某個 key 來取得 item 這個資料的某一筆資料,就像下面範例這樣,現在有個頁面一進去的時候後會把所有的員工資料給列出來,然後有個 input 我可以輸入該員工的編號,如果有這個員工,頁面上面只會秀出該員工,不然的話就會跳出沒有這個員工的錯誤訊息。

mike vue

看到這邊你會想說這樣什麼難的,直接秀一段 code

const searchId = 123
const searchItem = ItemArr.filter(item=> item.userId === searchId)
if(searchItem.length === 0){
  alert("查無此人")
}else{
  // show 彈窗
}

今天遇到像是這樣的情況最常見的就是透過 array 的 filter 去把我要的資料給篩選出來,簡單又快速,但是今天資料少,透過 filter 其實是最快的取得我們要的資料最快的方法,但是如果今天我們的這個 filter 會很頻繁地去使用,然後這個 list 的資料會越來越多的情況下,每次輸入都會重新的去執行 filter 會增加無謂的效能消耗,其實不是一個最好的解法,所以我們今天要介紹的其實是一種在特定情況下可以減少迴圈的使用,避免無謂的性能浪費的方法。

那就是把你現在的資料格式變成 map 的資料格式,這個 map 不是 Array 的 map,是一種資料結構的樣子,我們看一下這段範例的 code。

// 原本的樣子
[
  {
    createdAt: "2021-08-17T07:11:29.033Z",
    name: "Sonja Grady",
    avatar: "https://cdn.fakercloud.com/avatars/popey_128.jpg",
    userId: "399",
    username: "Clair.Langosh30",
    id: "1"
  },
  {
    createdAt: "2021-08-17T06:19:11.959Z",
    name: "Megan Mertz",
    avatar: "https://cdn.fakercloud.com/avatars/beshur_128.jpg",
    userId: "067",
    username: "Arlene_West",
    id: "2"
  },
  ...
]
// 我們要變成的樣子
{
   "399": {
      createdAt: "2021-08-17T07:11:29.033Z",
      name: "Sonja Grady",
      avatar: "https://cdn.fakercloud.com/avatars/popey_128.jpg",
      userId: "399",
      username: "Clair.Langosh30",
      id: "1"
   },
   "067": {
      createdAt: "2021-08-17T06:19:11.959Z",
      name: "Megan Mertz",
      avatar: "https://cdn.fakercloud.com/avatars/beshur_128.jpg",
      userId: "067",
      username: "Arlene_West",
      id: "2"
   },
	 ...
}

要怎麼把原本的資料格式變成現在物件包物件,然後是使用裡面的 userId來當作我物件的 key 呢? 其實只要這樣跑一個迴圈,我們就可以重組資料格式。

const map = {}
for (const item of ItemArr) {
  map[item.userId] = item;
}

我們來看一下完整的 Vue 檔案

<script>
import axios from "axios";
import { onMounted, reactive, ref } from "vue";
export default {
  setup() {
    const employeeItme = ref({});
    const activeId = ref("");
    const isOpen = ref(false);

    const transformData = (itemArr) => {
      const map = {};
      for (const item of itemArr) {
        map[item.userId] = item;
      }
      return map;
    };

    const handleOpen = () => (isOpen.value = !isOpen.value);

    const searchEmployee = () => {
      if (employeeItme.value[activeId.value]) {
        handleOpen();
        return;
      }
      alert("查無此人");
      activeId.value = "";
    };

    onMounted(() => {
      axios
        .get("https://610cd85966dd8f0017b76eb5.mockapi.io/api/employee_list")
        .then((res) => {
          employeeItme.value = transformData(res.data);
        });
    });

    return {
      employeeItme,
      activeId,
      isOpen,
      handleOpen,
      searchEmployee,
    };
  },
};
</script>


<template>
  <div id="search">
    <input type="text" placeholder="請輸入編號" v-model="activeId" />
    <button @click="searchEmployee">查詢</button>
  </div>

  <ul class="item">
    <li v-for="item in employeeItme" :key="item.id">
      <img :src="item.avatar" alt="" />
      <div>
        <p>員工編號: {{ item.userId }}</p>
        <p>姓名: {{ item.username }}</p>
      </div>
    </li>
  </ul>

  <div v-if="isOpen" class="popup">
    <div class="card">
      <img :src="employeeItme[activeId]?.avatar" alt="" />
      <div>
        <p>員工編號: {{ employeeItme[activeId]?.userId }}</p>
        <p>姓名: {{ employeeItme[activeId]?.username }}</p>
      </div>
      <button id="close" @click="handleOpen">x</button>
    </div>
  </div>
</template>

首先

  1. 我在頁面 onMounted 的時候去打 API 抓取所有員工的資料。

  2. 然後執行了 transformData這個資料重組的函式,把重組的資料給塞入 employeeItme。

  3. 再來就把資料 employeeItme 給丟到畫面上去執行 v-for。

  4. 給我們的輸入匡綁定一個 activeId的 id,到時候就是拿這個輸入的 id 來去做查詢。

  5. 所以當我今天點擊 searchEmployee這個函式的時候,我就會去檢查我們 employeeItme 裡面有沒有 activeId 的這個 key,如果沒有,自然就會跳出錯誤訊息,如果有就會開啟彈窗。

  6. 再來我只要拿 activeId 還有 employeeItme 這個兩東西去做取值,我就可以在不執行任何 filter 的情況下,把我需要的資料給取出來了。

為什麼要這麼的麻煩另外轉一個 map 的資料格式? 你可能會這麼問...

因為當你每次 click 查詢的時候,如果今天你是使用 filter 它就會每次都去跑一次迴圈,你有100筆,他就跑100次,有1000筆,就跑1000次,說實話這樣真的沒有必要,所以今天我們拿它需要篩選的 userId 來當作他的 key,透過物件的取值,我們就可以不用每次都要跑迴圈,只要在第一次拿到資料的時候去重組,之後所有的操作就不會需要跑迴圈了,也可以減少瀏覽器不必要的效能消耗,是一個在重構優化上面的小技巧。

這個範例我有放到 codesandbox 上面,有興趣的朋友可以上去看一下
https://codesandbox.io/s/vue-data-map-demo-6h3c7

今天就先告一段落

這邊分享了一個我自己在開發上面常用到的小技巧,這個小技巧不一定是在框架上面會用到,一般的JS開發也是很常會使用的,只要在開發的過程中,這種開發上小細節處理的好,自然網站執行上面的效率也會高多了,好啦~我們明天見吧 !

Mike Vue

那如果對於Vue3不夠熟的話呢?

Ps. 購買的時候請登入或註冊該平台的會員,然後再使用下面連結進入網站點擊「立即購課」,這樣才可以讓我獲得更多的課程分潤,還可以幫助我完成更多豐富的內容給各位。

我有開設了一堂專門針對Vue3從零開始教學的課程,如果你覺得不錯的話,可以購買我課程來學習
https://hiskio.com/bundles/9WwPNYRpz?s=tc

那如果對於JS基礎不熟的朋友,我也有開設JS的入門課程,可以參考這個課程
https://hiskio.com/bundles/b9Rovqy7z?s=tc

訂閱Mike的頻道享受精彩的教學與分享

Mike 的 Youtube 頻道
Mike的medium
MIke 的官方 line 帳號,好友搜尋 @mike_cheng


上一篇
[重構倒數第18天] - 我如何再Vue裡面使用axios有效管理API
下一篇
[重構倒數第16天] - 選擇套件給我好好選啊!
系列文
[ 重構倒數30天,你的網站不Vue白不Vue ] 共 32 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言