JSFiddle - React, Tailwind, and code Playground
by skirtle
HTML
<script src="https://unpkg.com/[email protected]/dist/vue.global.js"></script>
<div id="app">
<my-child :key="key"></my-child>
<button @click="key++">
Click to break the size updates
</button>
</div>
JavaScript
// This example illustrates how a computed ref is 'destroyed'.
// In this example the ref is created while the `setup` function
// of the child component is running. Because of that it is tied
// to that component and is destroyed when that component is
// destroyed. However, in this case that is undesirable because the
// computed ref is not specifically tied to that component, it just
// happens to be lazily created at that point. There are simple
// ways to work around this but it isn't immediately obvious why it
// happens unless you know about the destruction magic.
let width = null
let height = null
let size = null
// A composable for tracking the size of the browser viewport.
// As there can only be one viewport it tries to reuse as much
// as possible between the components that use it.
const useViewportSize = () => {
// Lazily create everything the first time we're used
if (!width) {
width = Vue.ref(null)
height = Vue.ref(null)
// This is the problem. The lazy creation of this
// computed ref occurs while setup is running
size = Vue.computed(() => `${width.value} x ${height.value}`)
const onResize = () => {
width.value = window.innerWidth
height.value = window.innerHeight
}
// Trigger immediately
onResize()
window.addEventListener('resize', onResize)
}
return {
width, height, size
}
}
const MyChild = {
template: `<div>{{ size }}</div>`,
setup () {
const { size } = useViewportSize()
return {
size
}
}
}
Vue.createApp({
components: { MyChild },
data () {
// The key is used to force the component to be destroyed
return { key: 1 }
}
}).mount('#app')