[重构倒数第17天] - 重组资料格式减少不必要的回圈执行

前言

该系列是为了让看过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


<<:  【Day14】变数的地盘—作用域(scoop)与提升(Hoisting)

>>:  Day 9 运算宝石:EC2 重点架构

Day 22 来写一个简单e2e测试

今天我们来写一个简单的form来当作测试吧,首先我们刻出一个简单的画面 const App: FC ...

Day 5 学习前人的隐私条款设计

Day 4提到过往我们如何拟出一份适用符合内部及市场的隐私条款,今天还是以隐私条款为主要探讨方向,在...

从pyside2 快速移植到pyside6的方法

目前稳定的主流是PyQt 5, PySide2 也是对应到这个版本。但从下个版本开始就改成 PySi...

30天打造品牌特色电商网站 Day.20 网站图片排版

图片是网站关键的视觉元素,更不用说电商网站了,相信大家都会在图片下功夫,让商品能够更加吸引顾客购买。...

Day29_CSS3

突然回到CSS好像有点跳tone,主要是因为在CSS & Javascript的基础不够熟练...