Why does Vue 3's Composition API have no onCreated hook, and which Options API hooks does `<script setup>` code replace?
answer
- setup runs before every option
- the script body is the hook
- beforeCreate and created
- beforeUnmount replaced beforeDestroy
basics
~20 ssetup() itself runs at the point where beforeCreate and created would, and in fact before both, so code written directly in <script setup> is the created phase. A separate onCreated hook would add nothing, so Vue does not provide one.
solid answer
~40 sIn the Options API, `beforeCreate` runs when the instance is initialised and `created` after data, computed, methods and watchers are set up, still before mounting. In the Composition API, `setup()` (the body of `<script setup>`) runs once at that same stage, and the Vue docs note it runs before any Options API hook, even `beforeCreate`. Whatever you would put in `created`, starting a request or initialising state, you write directly in the script body. That is why the Composition API has `onBeforeMount`, `onMounted` and so on but no `onBeforeCreate` or `onCreated`. On the teardown side, Vue 3 names the options `beforeUnmount` and `unmounted` (Vue 2's `beforeDestroy` and `destroyed`), with `onBeforeUnmount` and `onUnmounted` as the Composition API equivalents.
go deeper
Recall that the body of script setup plays the role of beforeCreate and created, and that the Vue 3 teardown options are beforeUnmount and unmounted.
Explain that setup runs before beforeCreate, what created guarantees in the Options API, and the order when both APIs are mixed in one component.
Use the mixed-API order when migrating components incrementally, and catch reviews that wrap created-phase code in onBeforeMount and so delay it for no reason.
Decide how far a codebase mixes the two APIs: mixing is supported, but a single convention keeps the lifecycle story simple for every reader.
## Two APIs, one lifecycle Vue 3 components can be written with the **Options API** (an object of `data`, `methods`, lifecycle options like `created` and `mounted`) or the **Composition API** (a `setup()` function, usually written as `<script setup>`, calling functions such as `onMounted`). Both drive the same internal lifecycle, so every Options API hook has a place in the Composition API. For the first two, that place is `setup()` itself. ## What beforeCreate and created mean - **`beforeCreate`**: called immediately when the instance is initialised and props are resolved, before `data()` and `computed` are set up. - **`created`**: called after the instance has processed all state-related options: reactive data, computed properties, methods and watchers exist. Mounting has not started, and `$el` is not available. Both exist so Options API code has a moment to run between "the instance exists" and "the instance renders". ## Why setup makes them redundant The Composition API **is** that moment. `setup()` runs once per instance, after props are resolved and before the first render. The Vue reference is explicit: the `setup()` hook of the Composition API is called **before any Options API hooks, even `beforeCreate()`**. So: 1. The props are already available in setup. 2. Reactive state you declare with `ref` or `reactive` exists as soon as the line runs. 3. Nothing has been rendered yet. A hypothetical `onCreated(() => { ... })` would run code at the point the script body is already running, so it would just be an extra indirection. Vue therefore exports `onBeforeMount`, `onMounted`, `onBeforeUpdate`, `onUpdated`, `onBeforeUnmount`, `onUnmounted` and a few others, but no creation hooks. ## Mapping table | Options API | Composition API (`<script setup>`) | |---|---| | `beforeCreate` | code in the script body (setup runs even earlier) | | `created` | code in the script body | | `beforeMount` | `onBeforeMount` | | `mounted` | `onMounted` | | `beforeUnmount` | `onBeforeUnmount` | | `unmounted` | `onUnmounted` | The last two rows are the Vue 3 names. Vue 2 called them `beforeDestroy` and `destroyed`; Vue 3 renamed them to match the mount/unmount vocabulary of the rest of the API. ## Mixing the two APIs in one component A component may define both `setup()` and Options API hooks. The order is then: - `setup()` first, - then `beforeCreate`, then `created`, - then `beforeMount`/`onBeforeMount` and the rest of the mount phase. A `created` option can read what `setup()` returned, but `setup()` cannot see anything the options create, because it runs before them. This matters when migrating a large component piece by piece. ## A migration example An Options API component that loads a profile when it is created: ```js export default { props: ['userId'], data() { return { profile: null } }, created() { loadProfile(this.userId).then(p => { this.profile = p }) }, beforeUnmount() { cancelPendingLoads() } } ``` becomes, in `<script setup>`: ```ts import { ref, onBeforeUnmount } from 'vue' // Profile, loadProfile and cancelPendingLoads come from the app's own module const props = defineProps<{ userId: string }>() const profile = ref<Profile | null>(null) loadProfile(props.userId).then(p => { profile.value = p }) // was created() onBeforeUnmount(() => cancelPendingLoads()) ``` The `created` body moves to the top level of the script unchanged in meaning; only the teardown needs a hook. ## Common misreadings - **"Code in `<script setup>` runs on every render."** It runs once per instance; only the template's render function re-runs on updates. - **"`onBeforeMount` is the Composition API's `created`."** It runs later, right before the first render; the script body is the equivalent. - **"`created` is gone in Vue 3."** It still exists as an Options API option; only the Composition API has no function form of it. ## How to phrase it in an interview State that `setup()` runs before `beforeCreate`, so the script body is where created-phase code goes, name the Vue 3 unmount option names, and mention that the Options API still supports `created` for components written in that style.
- If a Vue 3 component defines both setup() and a created option, which runs first and what can each see?`setup()` runs first, before even `beforeCreate`. The `created` option runs afterwards and can access what `setup()` returned through `this`, along with data, computed and methods. `setup()` cannot access Options API state, because none of it exists yet when setup runs.
- Does code at the top of a Vue 3 <script setup> block run again when the component re-renders?No. The script body is the component's `setup()`, which runs once per instance. Re-renders re-run only the compiled render function of the template, reading the reactive state that setup created. That is one of the key differences from function components that re-run their body on every render.
saying these in an interview costs you the question
- onBeforeMount is the Composition API version of created
- Vue 3 removed the created option entirely
- setup runs after created, once data is initialised
- Code in script setup runs on every re-render
- beforeDestroy is still the Vue 3 option name for teardown