2
This article was first published on the WeChat public account: Big Move to the World, my WeChat: qq449245884, I will share with you the front-end industry trends, learning methods, etc. as soon as possible.
For more open source works, please see GitHub https://github.com/qq449245884/xiaozhi , including the complete test sites, materials and my series of articles for interviews with first-tier manufacturers.

If you are using Vue to develop the project, then you may have visited slot.default() and encountered the following problems:

 Slot "default" invoked outside of the render function:
this will not track dependencies used in the slot. 
Invoke the slot function inside the render function instead.

In this article, the reasons behind this error and how to fix it will be explained.

The invocation of the slot needs to happen in the render function or template. To suppress this error, we just need to move the code into a computed property or method called from a template or render function.

What does "this will not track dependencies used in the slot" refer to?

The error message explains the root cause of the problem, but the hint is not clear enough to help us define the nature of the problem. Below, we will introduce the reasons behind the error in detail.

this will not track dependencies used in the slot.

After some investigation, I made a reproducible code and understood the implications of using the slots.default() syntax outside of the render function. To understand this, let's review Vue's reactivity principles first.

Vue's reactivity system allows us to declare properties, data and computed properties without tracking their changes. The responsiveness system works behind the scenes to ensure our variables are always up to date.

In the Vue framework, the most common case of reactive features is to use computed :

A computed property refers to a variable that can be used to modify and manipulate data and properties in your component in an efficient and reactive manner.

A simple example of a computed property is a blog snippet, where we pass a full blog post as a property and truncate it to a certain number of characters. Another more common example is a simple variable that defines the text of a button to "show" or "hide" depending on the current state.

For example, the following properties will never be run again until the value of "expanded" is changed.

 const buttonText = computed( () => {
  return expanded.value ? 'Show less' : 'Show more';
});

The above method will no longer be triggered unless the value of expanded changes. The observation that Vue is doing behind the scenes expanded the work of variables is what is called "tracking dependencies".

As you may have realized, the words "tracking dependencies" are the same as the Vue framework's error when trying to access a slot. In fact, this error is there to tell us that using the syntax slots.default() outside the render function makes the variable unresponsive, so it doesn't "track" any changes that might affect it.

Taking the example above, losing track of dependencies would mean that no matter what the value of expanded is, the button won't change.

 // 下面的代码只是为了说明问题
//  我们只是假设了一个具有跟踪依赖性的变量,这也是我们插槽发生的情况
const expanded = ref( false ); //Broken Tracking

console.log(buttonText)
// 输出 "Show more"

expanded.value = true;

console.log(buttonText)
// 输出: "Show more"  值没有没有改变,因为Vue无法跟踪 expanded 的变化。

Untracked variables are not something we want in our codebase and should be avoided as much as possible.

How to ensure Vue slots are tracked dependencies

Next, we analyze what can be done to ensure that our slots have a responsive tracking system to ensure that updates do not fail

By making sure our slot calls happen in render functions and templates, the problem is solved, as mentioned in the error message.

Invoke the slot function inside the render function

We are now going to introduce two different cases. The first is to call the slot function when using the render function, and the second is to use the <template> part of the vue single-file component.

Using slots in render functions

When using slots in a component that has a render function, we must make sure to call the slot function in the render function's "return" statement, not in setup .

 // 不好
import { h } from 'vue'

export default {
  setup( props, { slots } ) {
    const defaultSlot = slots.default();
    return () => h('div', defaultSlot)
  }
}

// 好
import { h } from 'vue'

export default {
  setup( props, { slots } ) {
    return () => h('div', slots.default())
  }
}

Using Slots When Using Single File Components (SFC)

If you use a single-file component and declare the HTML with the <template> block, you might think that you can't access the render function directly, but that's not the case.

When I first encountered this problem, I spent some time trying to understand how to move the slot function in the render function, but after Spa, I remembered <template> tags are converted by the compiler for us into a render function.

Knowing that <template> blocks and render functions are equivalent, goes a long way in defining our solution to a problem. In fact, to get rid of the warning and ensure dependencies are tracked in our components, we need to ensure that the invocation of the slot happens in the HTML (which is then compiled into a render function by the framework).

for example:

 // 缺点 - 如插槽改变,它将不会改变
<template>
  <div :class="{ 'style-for-svg': isSvg }">
    <slot></slot>
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
  setup( props, { slots } ) {
    const isSvg = ref( false );

    if( slots.default()[0].type === 'svg' ) {
      isSvg.value = true;
    }

    return {
      isSvg
    }
  }
}
</script>


// 优点:插槽改变,跟着变化
<template>
  <div :class="{ 'style-for-svg': $slots.default()[0].type === 'svg' }">
    <slot></slot>
  </div>
</template>

<script>

export default {
  setup( ) {
  }
}
</script>

Solving this problem is simple. Adding a function call directly to the template solves our problem. Unfortunately, the solution code above is not concise enough.

How to do it? Use computed properties.

During the investigation, computed properties are also compiled as part of the render function, which can be used to make the code more readable and still keep the variables reactive.

 <template>
  <div :class="{ 'style-for-svg': isSvg }">
    <slot></slot>
  </div>
</template>

<script>
import { computed } from 'vue'

export default {
  setup( ) {

    const isSvg = computed( () => {
      return slots.default()[0].type === 'svg';
    } );

    return {
       isSvg
    }

  }
}
</script>

Summarize

When developing Vue components, it's not very common to need access to slot functions, but if you do, I hope the solution above will save you some time.

The bugs that may exist after the code is deployed cannot be known in real time. In order to solve these bugs afterwards, a lot of time is spent on log debugging. By the way, I recommend a useful bug monitoring tool , Fundebug .

comminicate

If you have dreams and dry goods, you can search for [Great Move to the World] on WeChat and pay attention to this Shawanzhi who is still washing dishes in the early hours of the morning.

This article GitHub https://github.com/qq449245884/xiaozhi has been included, there are complete test sites, materials and my series of articles for interviews with first-line manufacturers.


王大冶
68k 声望104.9k 粉丝