Frontend๐ŸŽจ/Vue3.js๐Ÿ€

[Vue] watch์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž

JanuDev 2024. 12. 29. 00:14

๋‚˜๋„ ์„ ๋ฐฐ ๊ฐœ๋ฐœ์ž๋ถ„๋“ค์ฒ˜๋Ÿผ watch๋กœ ๋””๋ฒ„๊ทธ ํ•˜๊ณ ์‹ถ์–ด์„œ ์“ฐ๋Š” ๊ธ€

 

1. watch๋ž€ ๋ฌด์—‡์ธ๊ฐ€

Vue3 Composition API์—์„œ ๋ฐ˜์‘ํ˜• ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์‹œํ•˜๊ณ , ๋ณ€ํ™”๊ฐ€ ์ƒ๊ธธ ๊ฒฝ์šฐ ํŠน์ • ๋กœ์ง(=์ฝœ๋ฐฑํ•จ์ˆ˜)๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

์ฃผ๋กœ ๋ฐ˜์‘ํ˜• ๋ฐ์ดํ„ฐ(ref, reactive)์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” ์ž‘์—…์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค.

  1. ๋ฐ์ดํ„ฐ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ - ํŠน์ • ์ž‘์—… ํŠธ๋ฆฌ๊ฑฐ
  2. ๋น„๋™๊ธฐ ๋กœ์ง ์ˆ˜ํ–‰(ex. APIํ˜ธ์ถœ)
  3. ๋””๋ฒ„๊น…์— ์œ ์šฉ(๋‚ด๊ฐ€ ์ œ์ผ ๋ฐฐ์šฐ๊ณ  ์‹ถ์€ ์ด์œ !!!!!!1!)
  4. ๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง ๋ฐฉ์ง€ ๋“ฑ

2. watch์˜ ๊ตฌ์กฐ

watch(source, callback, options?)
  • source : ๊ฐ์‹œ ๋Œ€์ƒ. ๊ฐ์‹œํ•  ref๋‚˜ reactive, getterํ•จ์ˆ˜, ๋ฐฐ์—ด๋กœ ์ „๋‹ฌ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • callback : ๊ฐ์ง€๋œ ๋ณ€ํ™”๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์‹คํ–‰ํ•  ํ•จ์ˆ˜. ์ฆ‰ ์ฝœ๋ฐฑํ•จ์ˆ˜์ด๋‹ค. ๋‘ ๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜(์ƒˆ ๊ฐ’ newValue, ์ด์ „ ๊ฐ’ oldValue)๋ฅผ ๊ฐ€์ง„๋‹ค.
  • options : ์ถ”๊ฐ€ ์„ค์ •์„ ์œ„ํ•œ ๊ฐ์ฒด. ์ฃผ๋กœ immediate์™€ deep๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋”๋ผ.
    • immediate :  ๊ฐ์‹œ์ž๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ์ฆ‰์‹œ ์ฝœ๋ฐฑ ํ˜ธ์ถœ. ์ตœ์ดˆ ํ˜ธ์ถœ ์‹œ ์ด์ „ ๊ฐ’์€ undefined
    • deep : ์ „๋‹ฌ๊ฐ’ ์†Œ์Šค(=source)๊ฐ€ ๊ฐ์ฒด์ธ ๊ฒฝ์šฐ, ๊นŠ์€ ๋ณ€๊ฒฝ์‚ฌํ•ญ์—๋„ ์ฝœ๋ฐฑ์ด ์‹คํ–‰๋˜๋„๋ก ํ•œ๋‹ค. ๊ฐ์ฒด ๋‚ด๋ถ€๊นŒ์ง€ ๊นŠ์€ ๊ฐ์‹œ ์ˆ˜ํ–‰
    • flush : ์ฝœ๋ฐฑ์˜ ๋ฐœ์ƒ ํƒ€์ด๋ฐ์„ ์กฐ์ •ํ•œ๋‹ค(watchEffect)
    • onTrack / onTrigger : ๊ฐ์‹œ์ž์˜ ์˜์กด์„ฑ์„ ๋””๋ฒ„๊ทธํ•œ๋‹ค.
    • once : ์ฝœ๋ฐฑ์„ ํ•œ๋ฒˆ๋งŒ ์‹คํ–‰ํ•œ๋‹ค. ์ฒซ๋ฒˆ์งธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ ํ›„ ์ž๋™์œผ๋กœ ์ค‘์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

3. watch์˜ ์‚ฌ์šฉ๋ฒ•โญโญ

์‚ฌ์‹ค์ƒ ์˜ค๋Š˜ ํฌ์ŠคํŒ…์—์„œ ์ œ์ผ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด๋‹ค.

 

๊ธฐ๋ณธ ์‚ฌ์šฉ

  •  ref๊ฐ์‹œ
const count = ref(0);

watch(count, (newValue, oldValue) => {
  console.log(`Count changed from ${oldVal} to ${newVal}`);
});
  • getter(reactive) ๊ฐ์‹œ
const state = reactive({ count:0 });
watch(()=>state.count, (newValue, oldValue)=>{
  // newValue์—๋Š” ์ฆ๊ฐ€๋œ count๊ฐ’, oldValue์—๋Š” ๊ธฐ์กด์˜ count๊ฐ’์ด ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค. 
});
  • immediate ์‹คํ–‰
const keyword = ref('');

watch(keyword, (newValue) => {
  console.log('์ฐพ๋Š” ๊ฐ’ : ', newValue);
}, { immediate : true });

watch์„ค์ • ์งํ›„, ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์‹œ ํ•œ๋ฒˆ์€ ๋ฌด์กฐ๊ฑด ์‹คํ–‰ ๋œ๋‹ค. ๋”ฐ๋กœ ๋‚ด๊ฐ€ newValue๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„!

  • deep ์‹คํ–‰
const ninja = reactive({
  name : 'Naruto',
  age : 15,
  favouriteFood : 'Ramen',
});

// reactive์™€ ๊ฐ™์€ ๊ฐ์ฒด๋ฐ์ดํ„ฐ์ด๋ฏ€๋กœ source๋„ ํ•จ์ˆ˜๊ผด์ด์–ด์•ผ ํ•œ๋‹ค.
watch(
  () => ninja,
  (newValue, oldValue) => {
    // ๊ฐ์ฒด๊ฐ€ ์‚ฌ์Šค์ผ€๋กœ ๋ฐ”๋€๋‹ค๋ฉด newValue์—๋Š” ์‚ฌ์Šค์ผ€๊ฐ€, oldValue์—๋Š” ๋‚˜๋ฃจํ† ๊ฐ€ ๋“ค์–ด๊ฐˆ ๊ฒƒ์ด๋‹ค.
  }, {deep:true}
);

์—ฌ๊ธฐ์„  ninja ๊ฐ์ฒด์˜ name, age, favouriteFood ์ „๋ถ€ ๋‹ค ๊ฐ์ง€ํ•œ๋‹ค.

 

4. watch์™€ computed์˜ ์ฐจ์ด์ ?

๋‘˜ ๋‹ค Vue์—์„œ ์ƒํƒœ ๋ณ€ํ™”์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์— ์‚ฌ์šฉ๋˜์ง€๋งŒ, ๋™์ž‘ ๋ฐฉ์‹์—์„œ ๋‹ค์†Œ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

watch

  • ๋ฐ์ดํ„ฐ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•ด ๋ถ€์ˆ˜์ ์ธ ์ž‘์—…(=api ํ˜ธ์ถœ, ๋””๋ฒ„๊น…)์„ ์‹œํ–‰ํ•จ
  • ์ง€์ •ํ•œ ์ฝœ๋ฐฑํ•จ์ˆ˜ ์‹คํ–‰
  • ๋น„๋™๊ธฐ ์ž‘์—…์— ์ ํ•ฉํ•จ(setTimeout๊ณผ ๊ฐ™์€๊ฒƒ)
// count๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด alert ์‹คํ–‰

const count = ref(0);

watch(count, (newValue)=>{
  alert(newValue, 'ํšŒ ๋ˆŒ๋Ÿฌ์ง');
});

computed

  • ์ƒˆ๋กœ์šด ๊ฐ’ ๊ณ„์‚ฐ, ์บ์‹ฑ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณต
  • ๋ฐ์ดํ„ฐ ๋ณ€ํ™” ์‹œ ์ƒˆ๋กœ์šด ๊ฐ’ ๊ณ„์‚ฐ ํ›„ ์บ์‹ฑ
  • ๋น„๋™๊ธฐ ์ž‘์—… ์ง€์› ์•ˆํ•จ
const givenName = ref('Naruto');
const familyName = ref('Uzumaki');

// givenName๊ณผ familyName์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค. 
const fullName = computed(()=>{ 
  `${familyName.value} ${givenName.value}` // Uzumaki Naruto ์ถœ๋ ฅ๋จ
});

giveName.value = 'Sasuke';
familyName.value = 'Uchiha';

console.log(`${familyName.value} ${givenName.value}` ); // Uchiha Sasuke ์ถœ๋ ฅ๋จ

 

5. watch vs watchEffect

watch๋Š” source๊ฐ€ ๋ฐ˜๋“œ์‹œ ๋ช…์‹œ์ ์œผ๋กœ ํ•„์š”ํ•˜๋ฉฐ, newValue์™€ oldValue๋ฅผ ์ธ์ž๋กœ ๋ฐ›๋Š”๋‹ค.

๊ทธ๋ ‡์ง€๋งŒ ๊ทธ ๋ชจ๋“  ๊ฒƒ์„ ํ•œ๋ฐฉ์— ํ•„์š” ์—†๊ฒŒ๋” ๋งŒ๋“ค์–ด๋ฒ„๋ฆฌ๋Š” ์นœ๊ตฌ๊ฐ€ ๋ฐ”๋กœ watchEffect....

watchEffect๋Š” watch์™€ ๊ธฐ๋Šฅ์€ ๋น„์Šทํ•˜์ง€๋งŒ

โ‘  source๊ฐ€ ํ•„์š” ์—†๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๊ทธ๋ƒฅ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉ๋œ ๋ชจ๋“  ๋ฐ˜์‘ํ˜• ๋ฐ์ดํ„ฐ๊ฐ€ ์ข…์†๋œ๋‹ค.

โ‘ก ์ฝœ๋ฐฑ ํ•จ์ˆ˜์— ์ธ์ž๊ฐ€ ์ œ๊ณต๋˜์ง€ ์•Š๊ณ , ๋‚ด๋ถ€์—์„œ ์ƒํƒœ๋ฅผ ์ง์ ‘ ํ™•์ธํ•œ๋‹ค.

const count = ref(0);

watchEffect(()=>{
  console.log('๋ˆ„๋ฅธ ํšŸ์ˆ˜ :' , count.value);
});

// ref๊ฐ€ ์—ฌ๊ธฐ์„  count๋ฐ–์— ์—†์ง€๋งŒ
// name์ด๋‚˜ age ๋“ฑ์˜ ref๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ ์ƒ๊ธธ ๋•Œ์—๋„ watchEffectํ•จ์ˆ˜ ๋‚ด์— ์ž‘์„ฑํ•ด์„œ ๊ทธ๋ƒฅ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ์ƒํ™ฉ์—์„œ ๊ทธ๋ƒฅ watch๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ๊ฐ„๋‹จํ•œ๊ฒŒ ๋ฐ˜์‘ํ˜• ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ ํ•˜๊ฑฐ๋‚˜ ๊ฐ์‹œ ๋Œ€์ƒ ์ง€์ • ์—†์ด ์ƒํƒœ ๋ณ€ํ™”์— ๋ฐ˜์‘ํ•˜๋ ค ํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

watchEffect๋กœ ๊ท€์ฐฎ๊ฒŒ source ์„ค์ • ์—†์ด ๋””๋ฒ„๊น… ๊ฐ€๋Šฅํ• ์ง€๋„....?

 

+ ์ถ”๊ฐ€ ๊ถ๊ธˆ์ฆ

watch์—์„œ source์ž๋ฆฌ์— ์ผ๋ฐ˜๋ณ€์ˆ˜๋ฅผ ์“ธ ๋•Œ์™€  () => {}์˜ ์ฐจ์ด๋Š” ๋ฌด์—‡์ผ๊นŒ?

1. ์ผ๋ฐ˜ ๋ณ€์ˆ˜๋ฅผ source์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ

  • ์ผ๋ฐ˜ ๋ณ€์ˆ˜๋Š” refํ˜น์€ reactive๋กœ ์ถ”์ถœํ•œ ํŠน์ • ๋ณ€์ˆ˜๊ฐ€ ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
  • Vue๋Š” ์ด ๋ณ€์ˆ˜๋ฅผ ๋ฐ˜์‘ํ˜•์œผ๋กœ ์ถ”์ ํ•˜๊ณ , ๊ฐ’์ด ๋ฐ”๋€” ๋•Œ ๋งˆ๋‹ค ์ฝœ๋ฐฑ(callback)์ด ์‹คํ–‰๋œ๋‹ค.
  • ๊ฐ„๋‹จํ•œ "๋‹จ์ผ ๋ณ€์ˆ˜"๋ฅผ ๊ฐ์‹œํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

2. () => {}๋ฅผ source์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ

  • ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ ์ฐธ์กฐ๋œ ๋ฐ˜์‘ํ˜• ๊ฐ’๋“ค์„(()=>{}์•ˆ์— ์„ค์ •๋œ ๊ฐ’๋“ค)์„ ์ž๋™์œผ๋กœ ์ถ”์ ํ•œ๋‹ค.
  • ์ด ๋ณ€์ˆ˜๋“ค์„ ๊ฐ์ง€ํ•ด์„œ ์ฝœ๋ฐฑ(callback)์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๊ฐ™๋‹ค.
  • ํŠน์ • ์กฐ๊ฑด์ด๋‹ค ๊ณ„์‚ฐ๋œ ๊ฐ’, ์—ฌ๋Ÿฌ ๋ฐ˜์‘ํ˜• ๋ณ€์ˆ˜์˜ ์กฐํ•ฉ์„ ๊ฐ์‹œํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹จ์ผ๋ณ€์ˆ˜ ๋ฟ ๋งŒ ์•„๋‹ˆ๋ผ ๋ณต์žกํ•œ ๊ณ„์‚ฐ์‹(computed)๋‚˜ ์กฐ๊ฑด๋„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ณต์žกํ•œ ์กฐ๊ฑด, ๊ณ„์‚ฐ์‹(computed)๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ์— ์‚ฌ์šฉ๋œ๋‹ค.

 

[์ถœ์ฒ˜]

https://ko.vuejs.org/api/reactivity-core.html#watch

'Frontend๐ŸŽจ > Vue3.js๐Ÿ€' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

toValue()์™€ toRaw() (feat. MaybeRefOrGetter<T>, Proxy)  (0) 2025.10.02
[Vue] Vue-Query ์ด์ •๋ฆฌ  (0) 2025.01.05