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
dataRefchanges, the chart library needs to receive the wholedataRefand 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
initialRenderto skip initial render inwatchEffect()
Is this idiomatic Vue? I came from React where marking initial render like this is considered bad practice.
nextTickmight be useful so that it's sure that your DOM has properly been updated before doing anything fancy with your charts.