My sample:
<script setup lang="ts">
import { onMounted, ref, watchEffect } from "vue";
const htmlRef = ref("ref");
const dataRef = ref({});
onMounted(() => {
console.log("mount");
// Init with htmlRef
});
watchEffect(() => {
console.log("effect");
// Run after dataRef change
});
</script>
<template>
<div ref="ref"></div>
</template>
I have to integrate an external, pure JS chart with Vue.
- In the init step, the library needs access to DOM, so it must be in
onMounted()
. This does NOT contain the initial render. - Whenever
dataRef
changes, the chart library needs to receive the wholedataRef
and render again. SincewatchEffect()
runs eagerly, the initial render happens here naturally.
The only problem is that: init must be called before any render. Vue executes watchEffect()
before onMounted()
, so my code doesn’t work at all. Now how should I structure my code?
My current solution:
- Duplicate the render code. The initial render happens in
onMounted()
, and - Add a flag
initialRender
to skip initial render inwatchEffect()
Is this idiomatic Vue? I came from React where marking initial render like this is considered bad practice.