乐趣区

关于前端:如何解决在渲染函数之外调用插槽的问题

本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一工夫和你分享前端行业趋势,学习路径等等。
更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi,蕴含一线大厂面试残缺考点、材料以及我的系列文章。

如果你是用 Vue 来开发我的项目的,那么,你已经有可能拜访 slot.default() 遇到如下问题:

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. 

本文本中,将会解释这个谬误背地的起因以及如何解决这个问题。

插槽的调用须要产生在渲染函数或模板中。要克制这个谬误,咱们只须要把代码移到一个计算的属性或从模板或渲染函数中调用的办法中。

“this will not track dependencies used in the slot”指的是什么?

错误信息解释了问题产生的实质起因,但这个提醒不是很清晰,无奈帮忙咱们界定问题的实质。上面,咱们来具体介绍下谬误背地的起因产生。

this will not track dependencies used in the slot.

通过一些考察,我做了一个可复现的代码,并了解了在渲染函数之外应用 slots.default() 语法的含意。为了了解这个问题,咱们先温习一下 Vue 的响应式原理。

Vue 的响应式性零碎容许咱们申明属性、数据和计算属性,而不须要跟踪它们的变动。响应式性零碎在幕后工作,确保咱们的变量始终是最新的。

在 Vue 框架内,最常见的响应式特色的状况是应用 computed

计算属性指的是一个变量,它能够被用来以无效和响应式的形式批改和操作你的组件中的数据和属性。

计算属性的一个简略例子是博客片段,咱们把一篇残缺的博客文章作为属性传递,并把它截断成肯定数量的字符。另一个更常见的例子是一个简略的变量,用来定义一个按钮的文本,依据以后的状态 “ 显示 “ 或 “ 暗藏 ”。

举例来说,在 “expanded” 的值被扭转之前,上面的属性将永远不会再被运行。

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

除非 expanded 的值发生变化,否则上述办法不会再被触发。Vue 在幕后所做的察看 expanded 变量的工作就是所谓的 “ 跟踪依赖性 ”。

你可能曾经意识到了,” 跟踪依赖 ” 这几个字和 Vue 框架在试图拜访插槽时产生的谬误中提到的一样。事实上,这个谬误是为了通知咱们,在渲染函数之外应用 slots.default() 的语法,会使变量失去响应性,因而它不会 “ 跟踪 ” 任何可能影响它的变动。

拿下面的例子来说,失去依赖关系的跟踪将意味着无论 expanded 的值是多少,按钮都不会扭转。

// 上面的代码只是为了阐明问题
//  咱们只是假如了一个具备跟踪依赖性的变量,这也是咱们插槽产生的状况
const expanded = ref(false); //Broken Tracking

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

expanded.value = true;

console.log(buttonText)
// 输入: "Show more"  值没有没有扭转,因为 Vue 无奈跟踪 expanded 的变动。

在咱们的代码库中,未被追踪的变量不是咱们想要的货色,应该要尽量的防止它。

如何确保 Vue 插槽被跟踪依赖

接下来,咱们剖析下能够做些什么来确保咱们的插槽有一个响应式的跟踪零碎,确保不会更新失败

通过确保咱们的槽调用产生在渲染函数和模板中,问题就能够解决了,正如错误信息中提到的那样。

Invoke the slot function inside the render function

咱们当初要介绍两种不同的状况。第一种是在应用渲染函数时调用插槽函数,第二种是在应用 vue 单文件组件的 <template> 局部。

在渲染函数中应用插槽

当在一个有渲染函数的组件中应用插槽时,咱们必须确保在渲染函数的 “return” 语句中调用插槽函数,而不是在 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())
  }
}

在应用繁多文件组件(SFC)时应用插槽

如果应用单文件组件并应用 <template> 块申明 HTML,你可能会认为不能间接拜访渲染函数,但事实并非如此。

当我第一次遇到这个问题时,我花了一些工夫试图理解如何在渲染函数中挪动插槽函数,但在 Spa 之后,我想起了 <template>标签是由编译器为咱们转化成渲染函数的。

理解 <template> 块和渲染函数是等价的,对咱们定义解决问题的办法有很大帮忙。事实上,为了打消正告并确保在咱们的组件中跟踪依赖关系,咱们须要确保插槽的调用产生在 HTML 中(随后被框架编译成一个渲染函数)。

举个例子:


// 毛病 - 如插槽扭转,它将不会扭转
<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>

解决这个问题是很简略的。间接在模板中退出函数调用,就能够解决咱们的问题了。可怜的是,下面的解决方案代码不够简洁。

那要怎么做呢?应用计算属性。

在调查过程中,计算属性也被编译为渲染函数的一部分,能够用来使代码更易读,并且依然放弃变量的响应式。


<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>

总结

在开发 Vue 组件时,须要拜访插槽函数的状况并不常见,但如果你须要这样做,我心愿下面的解决方案能为你节俭一些工夫。

代码部署后可能存在的 BUG 没法实时晓得,预先为了解决这些 BUG,花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。

交换

有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

退出移动版