Vue optimization quick check

Starting portal: https://ssshooter.com/2021-03...

Split component

I also thought that dismantling molecular components was used for abstraction, but practice told me that dismantling molecular components was a way to improve performance (specific situation).

I have encountered such a problem in my actual work. There is a large table with multiple dialog boxes for adding items. When there is a lot of data, filling in the new data will change the card.

The reason is that in a component, modifying the value will cause the data check and diff of the whole component. But knowing that nothing has been changed in the big form, what else do I have to waste time checking?

In order to solve this problem, extracting the dialog box alone has become a very effective optimization method.

When the child component is updated, the parent component update will not be triggered by default, unless the child component changes the data of the parent component.

Let me take the dialog of element UI as an example:

Open this link Directly open the runnable case

Write a page, which contains two dialog s. One is written directly to the page, and the other is abstracted as a component.

<template>
  <div>
    <el-button type="text" @click="dialogVisible = true"
      >Click Open Dialog</el-button
    >
    <el-button type="text" @click="dialogData.visible = true"
      >Click Open Dialog2</el-button
    >
    <div>{{ renderAfter() }}</div>
    <el-dialog
      :append-to-body="true"
      title="Tips"
      :visible.sync="dialogVisible"
      width="30%"
    >
      <el-input v-model="xxx" />
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">Cancel</el-button>
        <el-button type="primary" @click="dialogVisible = false"
          >determine</el-button
        >
      </span>
    </el-dialog>
    <my-dialog :dialogData="dialogData" />
  </div>
</template>

<script>
  import MyDialog from './Dialog'
  export default {
    components: { MyDialog },
    name: 'HelloWorld',
    props: {
      msg: String,
    },
    data() {
      return {
        xxx: '',
        dialogVisible: false,
        dialogData: {
          visible: false,
        },
      }
    },
    methods: {
      renderAfter() {
        if (!window.renderCountTech) window.renderCountTech = 1
        else window.renderCountTech++
        console.log(
          '%c Rendering function detection',
          'color:#fff;background:red',
          window.renderCountTech
        )
      },
    },
  }
</script>

The following is the content of the dialog component:

<template>
  <el-dialog
    :append-to-body="true"
    title="Tips"
    :visible.sync="dialogData.visible"
    width="30%"
  >
    <el-input v-model="xxx" />
    <span slot="footer" class="dialog-footer">
      <el-button @click="dialogData.visible = false">Cancel</el-button>
      <el-button type="primary" @click="dialogData.visible = false"
        >determine</el-button
      >
    </span>
  </el-dialog>
</template>

<script>
  export default {
    props: ['dialogData'],
    data() {
      return {
        xxx: '',
      }
    },
  }
</script>

It can be seen from practice that the rendering function of the whole component will be triggered when dialog is opened and closed and the data is modified in the input box, while the parent component update will not be triggered when dialog2 is opened, closed or entered. If the amount of data in the component where the dialog box is located is small, there is really little difference, but when the amount is large, there will be perceptible Caton when entering in the dialog box. (in a word: the dialog box becomes a component, and internal updates do not affect the parent component)

More than that, conversely, when the parent component is updated, dialog1 will be rendered instead of dialog2, which is killing two birds with one stone. (in a word: when the parent component is updated, it does not change the child component without data change)

Even if this component is not reused, the methods used in the dialog box can be separated into separate files without mixing with the methods of the main page. If a dialog has a lot of logic, separating it into separate files is definitely a good method.

However, there are also disadvantages:

First of all, data interaction is a little inconvenient, but it can always be solved by using $parent and Vuex.

The second problem is to modify dialogdata Unexpected mutation of "dialogdata" prop will be reported when it is visible (vue/no-mutating-props).

As Vue's best practice, a parent-child prop cannot be modified directly by the child. My view is that if you know what you are doing and the side effects are not strong... It probably doesn't hurt to do so. What's your opinion?

If best practices are adhered to, there are two options:

emit

Honestly use on and emit, and a few more sentences of code:

<text-document v-bind:title.sync="doc.title"></text-document>

This is equal to:

<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>

Then in the sub component through this$ Emit ('update: title ', newtitle) updates the parent component.

$refs

The visibility is controlled by dialog itself. Set the visibility of dialog through refs in the parent component:

this.$refs.child.visible = true

And vice versa? You can also modify the father in the son (this is not to modify the prop, strange skills)

this.$parent.visible = true

A more detailed explanation of update granularity can be found here: What is the difference between Vue and React in the update granularity of components

PS: another hidden conclusion is that if a component uses slot, the child component will be re rendered with the parent component

computed

after Official documents It can be said that it is well known that computed can cache the calculation results and reduce the calculation consumption time when the dependent value remains unchanged.

Also known is the KeepAlive component.

Reduce the use of heavy components and plug-ins

Many UI frameworks are perfect, but just because they are too perfect, the interaction of various functions may make you run too slow or difficult to debug.

Of course, it's OK to directly change the original framework, but the understanding cost is not low, and it's even more difficult to merge the code after the change, so I prefer to make one myself.

I don't want to be a wheel that works all over the world. Because everyone's needs are different. If we want to make a wheel that meets everyone's requirements, the wheel will become very heavy. Personally, I don't want to see

Therefore, I hope that the "wheel" is a lightweight "framework" that meets the minimum functional requirements, so that it is convenient for everyone to modify, and at the same time, there is no need to worry about getting heavier and heavier with the continuous update. for example v-vld And [tbl]. ( https://github.com/v-cpn/cpn-tbl)

One way binding or even no binding at all

MDN Object.defineProperty()

One way binding means that the data uses defineProperty to set the configurable to false, so that the defineReactive corresponding to the data will skip the responsive setting:

Object.defineProperty(data, key, {
  configurable: false,
})

However, you can still assign a value to the bound target through v-model, but the interface will not be updated after the assignment.

This method works when the data is deeply nested. After blocking defineReactive, the sub objects in the data will not be processed recursively. (data flattening can also avoid recursion)

Completely unbound is the object written on the official website Freeze assigns a value to an object. In this way, the internal value of the object (the first layer) cannot be changed directly and can be applied to pure display data.

Caching ajax data

You can directly replace the original axios object by encapsulating it like the get of ordinary axios:

import axios from 'axios'
import router from './router'
import { Message } from 'element-ui'
let baseURL = process.env.VUE_APP_BASEURL
let ajax = axios.create({
  baseURL,
  withCredentials: true,
})
let ajaxCache = {}

ajaxCache.get = (...params) => {
  let url = params[0]
  let option = params[1]
  let id = baseURL + url + (option ? JSON.stringify(option.params) : '')
  if (sessionStorage[id]) {
    return Promise.resolve(JSON.parse(sessionStorage[id]))
  }
  return ajax.get(...params)
}

ajax.interceptors.response.use(
  function (response) {
    // Other processing
    // ......
    if (response.data.code === '20000') {
      let params = response.config.params
      let id = response.config.url + (params ? JSON.stringify(params) : '')
      sessionStorage[id] = JSON.stringify(response.data.data)
      return response.data.data
    }
  },
  function (error) {
    Message.error('connection timed out')
    return Promise.reject(error)
  }
)

export default ajaxCache

Functional component

<template functional>
  <div class="cell">
    <div v-if="props.value" class="on"></div>
    <section v-else class="off"></section>
  </div>
</template>

https://codesandbox.io/s/func...

PS: because functional components are not instantiated, they will be re rendered every time they are used. If you want to be completely static, use v-once

PS2: in Vue3, functional and normal component speeds The difference is almost negligible

Reduce the use of this

Simply put, it should be noted that the cost of this value every time in calculated, watch and render includes the code that depends on the collection. In fact, these codes only need to be run once.

{
  computed: {
    base () {
      return 42
    },
    result ({ base, start }) {
      let result = start
      for (let i = 0; i < 1000; i++) {
        result += Math.sqrt(Math.cos(Math.sin(base))) + base * base + base + base * 2 + base * 3
      }
      return result
    },
  },
}

To learn more about this problem, you can see here: https://mp.weixin.qq.com/s/wu...

v-show reusing DOM

Although v-show can speed up the display of components, the balance between v-show and v-if should also be mastered. v-if can be used to optimize the loading speed of the first screen.

Slice

  • Batch assignment of responsive data, so as to reduce the time of each rendering and improve the fluency perceived by users.
  • Delayed use of heavy if-v components
  • You can use requestAnimationFrame

Related portal: requestAnimationFrame

PS: personal experience. If multiple ajax involve the same pile of data, the speed of fragment rendering may not be fast. I will choose promise All merge rendering

summary

Component angle optimization:

  • Split components and optimize the update speed by using the update granularity at the component level
  • Use heavy components with caution. If necessary, make your own. The same is true for plug-ins
  • Use functional components (low priority)

Side effects of handling reactive:

  • Using responsive anti patterns
  • Reduce the use of this in dependency collection

Reduce rendering pressure:

  • The balance between v-show and v-if
  • Slice rendering

Vue's own cache:

  • keepalive
  • computed

Other optimizations:

  • Data cache
  • Virtual scrolling
  • Remove the console log
  • Enable performance configuration

Recommended articles

Keywords: Javascript Front-end Vue.js Optimize

Added by chelsea7 on Thu, 24 Feb 2022 12:10:31 +0200