Custom refs let you control how Vue tracks and updates reactive data. They help you create special reactive behaviors beyond the usual ones.
Custom refs with customRef in Vue
import { customRef } from 'vue' const myRef = customRef((track, trigger) => { let value return { get() { track() return value }, set(newValue) { value = newValue trigger() } } })
track() tells Vue to track dependencies when the value is read.
trigger() tells Vue to update dependents when the value changes.
const count = customRef((track, trigger) => { let value = 0 return { get() { track() return value }, set(newValue) { if (newValue >= 0) { value = newValue trigger() } } } })
const debouncedRef = customRef((track, trigger) => { let value let timeout return { get() { track() return value }, set(newValue) { clearTimeout(timeout) timeout = setTimeout(() => { value = newValue trigger() }, 300) } } })
This Vue component uses a custom ref to only update the count if the input is zero or positive. Negative numbers typed in the input will not change the displayed count.
<template>
<div>
<input v-model.number="count" type="number" aria-label="Number input" />
<p>Count (only positive numbers update): {{ count }}</p>
</div>
</template>
<script setup>
import { customRef } from 'vue'
const count = customRef((track, trigger) => {
let value = 0
return {
get() {
track()
return value
},
set(newValue) {
if (newValue >= 0) {
value = newValue
trigger()
}
}
}
})
</script>Use customRef when you need fine control over reactivity.
Always call track() in get() and trigger() in set() to keep Vue's reactivity system working.
Custom refs can help improve performance by reducing unnecessary updates.
Custom refs let you create reactive values with custom get/set behavior.
They use track() and trigger() to connect with Vue's reactivity.
Useful for debouncing, validation, or conditional updates.
Practice
customRef in Vue?Solution
Step 1: Understand what
customRefdoescustomRefallows you to create reactive references where you control how the value is read and written.Step 2: Compare with other options
Options A, C, and D relate to other Vue features, notcustomRef.Final Answer:
To create reactive references with custom get and set behavior -> Option AQuick Check:
customRef = custom reactive behavior [OK]
- Confusing customRef with component registration
- Thinking customRef manages lifecycle hooks
- Assuming customRef defines templates
customRef in a Vue 3 component?Solution
Step 1: Recall Vue 3 import syntax
Vue exportscustomRefas a named export, so it must be imported with curly braces.Step 2: Check each option
import { customRef } from 'vue'; uses correct named import syntax. import customRef from 'vue'; tries default import which is incorrect. import { CustomRef } from 'vue'; uses wrong capitalization. import * as customRef from 'vue'; imports everything as an object, which is not typical for this usage.Final Answer:
import { customRef } from 'vue'; -> Option CQuick Check:
Named import uses curly braces [OK]
- Using default import instead of named import
- Wrong capitalization of customRef
- Importing everything instead of named import
myRef.value = 10 is called?import { customRef } from 'vue';
const myRef = customRef((track, trigger) => {
let value = 0;
return {
get() {
track();
return value;
},
set(newValue) {
if (newValue !== value) {
value = newValue;
trigger();
console.log('Value updated');
}
}
};
});
myRef.value = 10;Solution
Step 1: Understand the set function behavior
The set function checks if the new value differs from the current one. Since 10 !== 0, it updates value, triggers reactivity, and logs 'Value updated'.Step 2: Confirm no repeated logs or errors
There is no repeated assignment or error in the code, so only one log occurs.Final Answer:
Value updated -> Option AQuick Check:
Set logs once on value change [OK]
- Expecting no output because of track confusion
- Thinking trigger causes multiple logs
- Assuming error due to track usage
import { customRef } from 'vue';
const myRef = customRef((track, trigger) => {
let value = 0;
return {
get() {
return value;
},
set(newValue) {
value = newValue;
trigger();
}
};
});Solution
Step 1: Check get() method for reactivity tracking
The get() method must calltrack()to register dependencies. Here, it returns value without calling track(), so reactivity won't work properly.Step 2: Verify other parts
Trigger is correctly called in set(). Value does not need to be a ref inside customRef. Arrow functions are allowed.Final Answer:
Missing call to track() inside get() -> Option DQuick Check:
track() needed in get() for reactivity [OK]
- Forgetting to call track() in get()
- Thinking trigger() is needed in get()
- Assuming value must be a ref inside customRef
customRef that debounces updates by 300ms before triggering reactivity. Which code snippet correctly implements this behavior?Solution
Step 1: Understand debounce logic in set()
Debounce means delaying the update and trigger until 300ms after the last set call. The correct code clears previous timeout, sets new timeout to update value and trigger after 300ms.Step 2: Check get() calls track()
The correct code calls track() in get() to register dependencies. Missing track() in get() breaks reactivity. The remaining options either lack track(), do not debounce properly, or have incorrect debouncing logic.Final Answer:
Correctly implements debounced updates with track() in get() -> Option BQuick Check:
Debounce needs clearTimeout + delayed trigger [OK]
- Not calling track() inside get()
- Triggering immediately without debounce
- Setting value outside timeout causing immediate update
Ready to prove it?
Pass the test and this pattern moves unknown
