DEV Community

Ryan John
Ryan John

Posted on • Originally published at vureact.top

How does VuReact compile Vue 3's watch() to React?

VuReact is a tool that compiles Vue 3 code into standard, maintainable React code. In this article, we will look at one of Vue's most important side-effect APIs: watch().

If you write watch() in Vue, what does VuReact generate for React?

Before We Dive In

To keep the article focused, these examples follow two small conventions:

  1. All Vue and React snippets show only the core logic, with full component wrappers and unrelated setup omitted.
  2. The discussion assumes you are already familiar with the API shape and core behavior of Vue 3 watch.

Compilation Mapping

Vue watch() -> React useWatch()

watch() is Vue 3's core API for observing reactive sources and running side effects when they change.

VuReact compiles it into useWatch(), and during compilation it can automatically analyze watch dependencies, perform precise tracking, and avoid the need for developers to manually manage dependency arrays.

  • Vue
<script setup>
import { ref, watch } from 'vue';

const userId = ref(1);

watch(
  userId,
  async (newId, oldId, onCleanup) => {
    let cancelled = false;

    onCleanup(() => {
      cancelled = true;
    });

    const data = await fetchUser(newId);
    if (!cancelled) {
      userData.value = data;
    }
  },
  { immediate: true },
);
</script>
Enter fullscreen mode Exit fullscreen mode
  • Compiled React
import { useVRef, useWatch } from '@vureact/runtime-core';

const userId = useVRef(1);

useWatch(
  userId,
  async (newId, oldId, onCleanup) => {
    let cancelled = false;

    onCleanup(() => {
      cancelled = true;
    });

    const data = await fetchUser(newId);
    if (!cancelled) {
      setUserData(data);
    }
  },
  { immediate: true },
);
Enter fullscreen mode Exit fullscreen mode

As the example shows, Vue watch() maps directly to useWatch().

VuReact's useWatch is the runtime adapter for watch(). It preserves familiar Vue watch semantics, including callback behavior, cleanup handling, and the immediate option.

Deep and Multi-Source Watching Still Works

When watch() observes nested object state or multiple sources at once, VuReact still preserves the expected behavior.

  • Vue
<script setup>
import { reactive, watch } from 'vue';

const state = reactive({
  info: { name: 'VuReact', version: '1.0' },
  count: 0,
});

watch(
  () => state.info,
  (newInfo) => {
    console.log('nested change:', newInfo.name);
  },
  { deep: true },
);

watch([state.count, () => state.info.name], ([newCount, newName]) => {
  console.log('count:', newCount, 'name:', newName);
});
</script>
Enter fullscreen mode Exit fullscreen mode
  • Compiled React
import { useReactive, useWatch } from '@vureact/runtime-core';

const state = useReactive({
  info: { name: 'VuReact', version: '1.0' },
  count: 0,
});

useWatch(
  () => state.info,
  (newInfo) => {
    console.log('nested change:', newInfo.name);
  },
  { deep: true },
);

useWatch([state.count, () => state.info.name], ([newCount, newName]) => {
  console.log('count:', newCount, 'name:', newName);
});
Enter fullscreen mode Exit fullscreen mode

VuReact analyzes watch dependencies during compilation and generates the tracking logic needed to make both deep watching and array-based sources behave as expected, without forcing developers to maintain those dependencies by hand.

Top comments (0)