રિએક્ટિવિટી ફંડામેન્ટલ્સ
API પસંદગી (API Preference)
આ પૃષ્ઠ અને માર્ગદર્શિકાના પછીના ઘણા પ્રકરણો Options API અને Composition API માટે અલગ-અલગ સામગ્રી ધરાવે છે. તમારી વર્તમાન પસંદગી Composition API છે. તમે ડાબી સાઇડબારની ટોચ પરના "API Preference" સ્વીચનો ઉપયોગ કરીને API શૈલીઓ વચ્ચે બદલી શકો છો.
રિએક્ટિવ સ્ટેટ જાહેર કરવી
ref()
Composition API માં, રિએક્ટિવ સ્ટેટ જાહેર કરવાની ભલામણ કરેલ રીત એ ref() ફંક્શનનો ઉપયોગ છે:
js
import { ref } from 'vue'
const count = ref(0)ref() આર્ગ્યુમેન્ટ લે છે અને તેને .value પ્રોપર્ટી સાથેના રિફ (ref) ઓબ્જેક્ટની અંદર લપેટીને પરત કરે છે:
js
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1આ પણ જુઓ: Typing Refs
કમ્પોનન્ટના ટેમ્પલેટમાં રિફ્સ (refs) ને એક્સેસ કરવા માટે, તેમને કમ્પોનન્ટના setup() ફંક્શનમાંથી જાહેર કરો અને પરત કરો:
js
import { ref } from 'vue'
export default {
// `setup` એ Composition API માટે સમર્પિત એક વિશિષ્ટ હૂક છે.
setup() {
const count = ref(0)
// ટેમ્પલેટમાં ref એક્સપોઝ કરો
return {
count
}
}
}template
<div>{{ count }}</div>નોંધ લો કે ટેમ્પલેટમાં રિફનો ઉપયોગ કરતી વખતે અમારે .value જોડવાની જરૂર પડી નથી. સગવડ માટે, જ્યારે ટેમ્પલેટની અંદર ઉપયોગ કરવામાં આવે ત્યારે રિફ્સ આપોઆપ અનવ્રેપ (unwrap) થઈ જાય છે (થોડા અવરોધો સાથે).
તમે ઇવેન્ટ હેન્ડલર્સમાં સીધા જ ફેરફાર (mutate) કરી શકો છો:
template
<button @click="count++">
{{ count }}
</button>વધુ જટિલ લોજિક માટે, અમે સમાન સ્કોપ (scope) માં રિફ્સમાં ફેરફાર કરતા ફંક્શન્સ જાહેર કરી શકીએ છીએ અને તેમને સ્ટેટની સાથે મેથડ્સ તરીકે એક્સપોઝ કરી શકીએ છીએ:
js
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
function increment() {
// JavaScript માં .value જરૂરી છે
count.value++
}
// ફંક્શનને પણ એક્સપોઝ કરવાનું ભૂલશો નહીં.
return {
count,
increment
}
}
}એક્સપોઝ કરેલી મેથડ્સનો પછી ઇવેન્ટ હેન્ડલર્સ તરીકે ઉપયોગ કરી શકાય છે:
template
<button @click="increment">
{{ count }}
</button>કોઈપણ બિલ્ડ ટૂલ્સનો ઉપયોગ કર્યા વિના, Codepen પર આ ઉદાહરણ લાઈવ છે.
<script setup>
setup() દ્વારા મેન્યુઅલી સ્ટેટ અને મેથડ્સ એક્સપોઝ કરવી કંટાળાજનક હોઈ શકે છે. સદભાગ્યે, સિંગલ-ફાઇલ કમ્પોનન્ટ્સ (SFCs) નો ઉપયોગ કરતી વખતે તેને ટાળી શકાય છે. અમે <script setup> સાથે તેનો વપરાશ સરળ બનાવી શકીએ છીએ:
vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">
{{ count }}
</button>
</template><script setup> માં જાહેર કરવામાં આવેલા ટોપ-લેવલ ઇમ્પોર્ટ્સ, વેરિએબલ્સ અને ફંક્શન્સ સમાન ઘટકના ટેમ્પલેટમાં આપમેળે વાપરી શકાય તેવા હોય છે. ટેમ્પલેટને સમાન સ્કોપમાં જાહેર કરાયેલા જાવાસ્ક્રિપ્ટ ફંક્શન તરીકે વિચારો - તે સ્વાભાવિક રીતે તેની સાથે જાહેર કરાયેલ દરેક વસ્તુની એક્સેસ ધરાવે છે.
TIP
માર્ગદર્શિકાના બાકીના ભાગો માટે, અમે Composition API કોડ ઉદાહરણો માટે મુખ્યત્વે SFC + <script setup> સિન્ટેક્સનો ઉપયોગ કરીશું, કારણ કે Vue ડેવલપર્સ માટે તે સૌથી સામાન્ય વપરાશ છે.
જો તમે SFC નો ઉપયોગ કરી રહ્યાં નથી, તો પણ તમે setup() ઓપ્શન સાથે Composition API નો ઉપયોગ કરી શકો છો.
રિફ્સ (Refs) શા માટે?
તમે કદાચ વિચારતા હશો કે આપણને સાદા વેરિએબલ્સને બદલે .value સાથેના રિફ્સની કેમ જરૂર છે. તે સમજાવવા માટે, આપણે Vue ની રિએક્ટિવિટી સિસ્ટમ કેવી રીતે કાર્ય કરે છે તેની ટૂંકમાં ચર્ચા કરવાની જરૂર પડશે.
જ્યારે તમે ટેમ્પલેટમાં રિફનો ઉપયોગ કરો છો અને પછીથી રિફની વેલ્યુ બદલો છો, ત્યારે Vue આપમેળે ફેરફાર શોધી કાઢે છે અને તે મુજબ DOM ને અપડેટ કરે છે. આ ડિપેન્ડન્સી-ટ્રેકિંગ (dependency-tracking) આધારિત રિએક્ટિવિટી સિસ્ટમ સાથે શક્ય બન્યું છે. જ્યારે કોઈ ઘટક પ્રથમ વખત રેન્ડર થાય છે, ત્યારે Vue રેન્ડર દરમિયાન ઉપયોગમાં લેવાયેલા દરેક રિફને ટ્રૅક (tracks) કરે છે. બાદમાં, જ્યારે રિફમાં ફેરફાર કરવામાં આવે છે, ત્યારે તે તેને ટ્રૅક કરતા ઘટકો માટે ફરીથી રેન્ડર (re-render) કરવાનું ટ્રિગર (trigger) કરશે.
પ્રમાણભૂત JavaScript માં, સાદા વેરિએબલ્સની એક્સેસ અથવા ફેરફારને શોધવાનો કોઈ રસ્તો નથી. જો કે, અમે ગેટર (getter) અને સેટર (setter) મેથડનો ઉપયોગ કરીને ઓબ્જેક્ટની પ્રોપર્ટીઝના ગેટ અને સેટ ઓપરેશન્સને અટકાવી શકીએ છીએ.
.value પ્રોપર્ટી Vue ને એ શોધવાની તક આપે છે કે ક્યારે કોઈ રિફ એક્સેસ અથવા મ્યુટેટેડ (mutated) થઈ છે. અંદરથી, Vue તેના ગેટરમાં ટ્રેકિંગ કરે છે અને તેના સેટરમાં ટ્રિગરિંગ કરે છે. કલ્પનાત્મક રીતે, તમે રિફને એવા ઓબ્જેક્ટ તરીકે વિચારી શકો છો જે આના જેવો દેખાય છે:
js
// સ્યુડો કોડ, વાસ્તવિક અમલીકરણ નથી
const myRef = {
_value: 0,
get value() {
track()
return this._value
},
set value(newValue) {
this._value = newValue
trigger()
}
}રિફ્સનો બીજો સારો ગુણ એ છે કે સાદા વેરિએબલ્સથી વિપરીત, તમે નવીનતમ વેલ્યુ અને રિએક્ટિવિટી કનેક્શનની એક્સેસ જાળવી રાખીને રિફ્સને ફંક્શન્સમાં પાસ કરી શકો છો. જટિલ લોજિકને પુનઃઉપયોગી કોડમાં રિફેક્ટરિંગ કરતી વખતે આ ખાસ કરીને ઉપયોગી છે.
રિએક્ટિવિટી સિસ્ટમ વિશે વધુ વિગતવાર રિએક્ટિવિટી ઇન ડેપ્થ વિભાગમાં ચર્ચા કરવામાં આવી છે.
ડીપ (Deep) રિએક્ટિવિટી
રિફ્સ (Refs) કોઈપણ વેલ્યુ પ્રકાર ધરાવી શકે છે જેમાં ડીપલી નેસ્ટેડ ઓબ્જેક્ટ્સ, એરે અથવા JavaScript બિલ્ટ-ઇન ડેટા સ્ટ્રક્ચર્સ જેમ કે Map નો સમાવેશ થાય છે.
રિફ તેની વેલ્યુને ડીપલી રિએક્ટિવ બનાવશે. આનો અર્થ એ છે કે જ્યારે તમે નેસ્ટેડ ઓબ્જેક્ટ્સ અથવા એરેમાં ફેરફાર કરો છો ત્યારે પણ ફેરફારો શોધી શકાય છે:
js
import { ref } from 'vue'
const obj = ref({
nested: { count: 0 },
arr: ['foo', 'bar']
})
function mutateDeeply() {
// આ અપેક્ષા મુજબ કામ કરશે.
obj.value.nested.count++
obj.value.arr.push('baz')
}બિન-પ્રિમિટિવ (Non-primitive) મૂલ્યોને reactive() દ્વારા રિએક્ટિવ પ્રોક્સીમાં ફેરવવામાં આવે છે, જેની નીચે ચર્ચા કરવામાં આવી છે.
shallow refs સાથે ડીપ રિએક્ટિવિટી ને ઓપ્ટ-આઉટ (opt-out) કરવી પણ શક્ય છે. શેલો રિફ્સ (shallow refs) માટે, રિએક્ટિવિટી માટે ફક્ત .value એક્સેસ ટ્રૅક કરવામાં આવે છે. મોટા ઓબ્જેક્ટ્સના અવલોકન ખર્ચને ટાળીને અથવા જ્યાં આંતરિક સ્થિતિ બાહ્ય લાઇબ્રેરી દ્વારા સંચાલિત હોય તેવા કિસ્સાઓમાં પર્ફોર્મન્સ ઑપ્ટિમાઇઝ કરવા માટે શેલો રિફ્સનો ઉપયોગ કરી શકાય છે.
વધુ વાંચન:
DOM અપડેટ ટાઈમિંગ
જ્યારે તમે રિએક્ટિવ સ્ટેટમાં ફેરફાર કરો છો, ત્યારે DOM આપોઆપ અપડેટ થાય છે. જો કે, એ નોંધવું જોઈએ કે DOM અપડેટ્સ સિંક્રનસ (synchronously) રીતે લાગુ પડતા નથી. તેના બદલે, Vue તેમને અપડેટ ચક્રમાં "નેક્સ્ટ ટીક (next tick)" સુધી બફર (buffers) કરે છે જેથી ખાતરી કરી શકાય કે તમે કેટલા ડેટા ફેરફારો કર્યા છે તે મહત્વનું નથી, દરેક ઘટક માત્ર એક જ વાર અપડેટ થાય.
સ્ટેટ ફેરફાર પછી DOM અપડેટ પૂર્ણ થાય તેની રાહ જોવા માટે, તમે nextTick() ગ્લોબલ API નો ઉપયોગ કરી શકો છો:
js
import { nextTick } from 'vue'
async function increment() {
count.value++
await nextTick()
// હવે DOM અપડેટ થયેલ છે
}reactive()
રિએક્ટિવ સ્ટેટ જાહેર કરવાની બીજી રીત છે, જે reactive() API સાથે છે. રિફની વિપરીત જે આંતરિક વેલ્યુને વિશેષ ઓબ્જેક્ટમાં લપેટી લે છે, reactive() ઓબ્જેક્ટને પોતે જ રિએક્ટિવ બનાવે છે:
js
import { reactive } from 'vue'
const state = reactive({ count: 0 })આ પણ જુઓ: Typing Reactive
ટેમ્પલેટમાં વપરાશ:
template
<button @click="state.count++">
{{ state.count }}
</button>રિએક્ટિવ ઓબ્જેક્ટ્સ JavaScript Proxies છે અને સામાન્ય ઓબ્જેક્ટ્સની જેમ જ વર્તે છે. તફાવત એ છે કે Vue રિએક્ટિવિટી ટ્રેકિંગ અને ટ્રિગરીંગ માટે રિએક્ટિવ ઓબ્જેક્ટની તમામ પ્રોપર્ટીઝની એક્સેસ અને ફેરફારને અટકાવવા સક્ષમ છે.
reactive() ઓબ્જેક્ટને ડીપલી કન્વર્ટ કરે છે: જ્યારે એક્સેસ કરવામાં આવે ત્યારે નેસ્ટેડ ઓબ્જેક્ટ્સ પણ reactive() સાથે લપેટાયેલા હોય છે. જ્યારે રિફ વેલ્યુ ઓબ્જેક્ટ હોય ત્યારે તે આંતરિક રીતે ref() દ્વારા પણ કોલ કરવામાં આવે છે. શેલો રિફ્સની જેમ, ડીપ રિએક્ટિવિટીમાંથી ઓપ્ટ-આઉટ કરવા માટે shallowReactive() API પણ છે.
રિએક્ટિવ પ્રોક્સી વિરુદ્ધ અસલ
એ નોંધવું અગત્યનું છે કે reactive() માંથી પરત કરાયેલ વેલ્યુ અસલ ઓબ્જેક્ટની પ્રોક્સી (Proxy) છે, જે અસલ ઓબ્જેક્ટની સમાન નથી:
js
const raw = {}
const proxy = reactive(raw)
// પ્રોક્સી અસલ સમાન નથી.
console.log(proxy === raw) // falseસિર્ફ પ્રોક્સી જ રિએક્ટિવ છે - અસલ ઓબ્જેક્ટ બદલવાથી અપડેટ્સ ટ્રિગર થશે નહીં. તેથી, Vue ની રિએક્ટિવિટી સિસ્ટમ સાથે કામ કરતી વખતે શ્રેષ્ઠ અભ્યાસ એ છે કે તમારા સ્ટેટના પ્રોક્સિએડ વર્ઝનનો વિશિષ્ટ રીતે ઉપયોગ કરવો.
પ્રોક્સીની સુસંગત એક્સેસ સુનિશ્ચિત કરવા માટે, સમાન ઓબ્જેક્ટ પર reactive() ને કોલ કરવાથી હંમેશા સમાન પ્રોક્સી મળે છે, અને અસ્તિત્વમાં હોય તેવી પ્રોક્સી પર reactive() ને કોલ કરવાથી પણ તે જ પ્રોક્સી મળે છે:
js
// સમાન ઓબ્જેક્ટ પર reactive() કોલ કરવાથી તે જ પ્રોક્સી પરત મળે છે
console.log(reactive(raw) === proxy) // true
// પ્રોક્સી પર reactive() કોલ કરવાથી તે પોતે જ પરત મળે છે
console.log(reactive(proxy) === proxy) // trueઆ નિયમ નેસ્ટેડ ઓબ્જેક્ટ્સને પણ લાગુ પડે છે. ડીપ રિએક્ટિવિટીને કારણે, રિએક્ટિવ ઓબ્જેક્ટની અંદર નેસ્ટેડ ઓબ્જેક્ટ્સ પણ પ્રોક્સી છે:
js
const proxy = reactive({})
const raw = {}
proxy.nested = raw
console.log(proxy.nested === raw) // falsereactive() ની મર્યાદાઓ
reactive() API ની કેટલીક મર્યાદાઓ છે:
મર્યાદિત વેલ્યુ પ્રકારો: તે ફક્ત ઓબ્જેક્ટ પ્રકારો (ઓબ્જેક્ટ્સ, એરે અને કલેક્શન પ્રકારો જેમ કે
MapઅનેSet) માટે જ કામ કરે છે. તે પ્રિમિટિવ પ્રકારો જેમ કેstring,numberઅથવાbooleanને પકડી શકતું નથી.સમગ્ર ઓબ્જેક્ટને બદલી શકાતું નથી: કારણ કે Vue નું રિએક્ટિવિટી ટ્રેકિંગ પ્રોપર્ટી એક્સેસ પર કામ કરે છે, આપણે હંમેશા રિએક્ટિવ ઓબ્જેક્ટનો સમાન સંદર્ભ (reference) રાખવો જોઈએ. આનો અર્થ એ છે કે આપણે રિએક્ટિવ ઓબ્જેક્ટને સરળતાથી "બદલી" શકતા નથી કારણ કે પ્રથમ સંદર્ભ સાથેનું રિએક્ટિવિટી કનેક્શન ખોવાઈ જાય છે:
jslet state = reactive({ count: 0 }) // ઉપરનો સંદર્ભ ({ count: 0 }) હવે ટ્રૅક કરવામાં આવી રહ્યો નથી // (રિએક્ટિવિટી કનેક્શન ખોવાઈ ગયું છે!) state = reactive({ count: 1 })ડિસ્ટ્રક્ચર-ફ્રેન્ડલી નથી: જ્યારે આપણે રિએક્ટિવ ઓબ્જેક્ટની પ્રિમિટિવ ટાઈપ પ્રોપર્ટીને લોકલ વેરિએબલ્સમાં ડિસ્ટ્રક્ચર (destructure) કરીએ છીએ, અથવા જ્યારે આપણે તે પ્રોપર્ટીને ફંક્શનમાં પાસ કરીએ છીએ, ત્યારે આપણે રિએક્ટિવિટી કનેક્શન ગુમાવીશું:
jsconst state = reactive({ count: 0 }) // જ્યારે ડિસ્ટ્રક્ચર કરવામાં આવે ત્યારે count એ state.count થી ડિસ્કનેક્ટ થઈ જાય છે. let { count } = state // અસલ સ્ટેટ ને અસર કરતું નથી count++ // ફંક્શનને પ્લેન નંબર મળે છે અને // state.count માં થતા ફેરફારને ટ્રૅક કરી શકશે નહીં. // રિએક્ટિવિટી જાળવવા માટે આપણે આખો ઓબ્જેક્ટ પાસ કરવો પડશે callSomeFunction(state.count)
આ મર્યાદાઓને કારણે, અમે રિએક્ટિવ સ્ટેટ જાહેર કરવા માટે પ્રાથમિક API તરીકે ref() નો ઉપયોગ કરવાની ભલામણ કરીએ છીએ.
વધારાના રિફ અનવ્રેપિંગ (Ref Unwrapping) ની વિગતો
રિએક્ટિવ ઓબ્જેક્ટ પ્રોપર્ટી તરીકે
જ્યારે રિએક્ટિવ ઓબ્જેક્ટની પ્રોપર્ટી તરીકે એક્સેસ અથવા મ્યુટેટેડ કરવામાં આવે ત્યારે રિફ આપમેળે અનવ્રેપ (unwrap) થાય છે. બીજા શબ્દોમાં કહીએ તો, તે સામાન્ય પ્રોપર્ટીની જેમ વર્તે છે:
js
const count = ref(0)
const state = reactive({
count
})
console.log(state.count) // 0
state.count = 1
console.log(count.value) // 1જો હાલના રિફ સાથે લિંક કરેલી પ્રોપર્ટીને નવો રિફ અસાઇન કરવામાં આવે, તો તે જૂના રિફને બદલી દેશે:
js
const otherCount = ref(2)
state.count = otherCount
console.log(state.count) // 2
// અસલ રિફ હવે state.count થી ડિસ્કનેક્ટ થઈ ગયો છે
console.log(count.value) // 1રિફ અનવ્રેપિંગ ફક્ત ત્યારે જ થાય છે જ્યારે ડીપ રિએક્ટિવ ઓબ્જેક્ટની અંદર નેસ્ટ થયેલ હોય. જ્યારે તેને શેલો રિએક્ટિવ ઓબ્જેક્ટ (shallow reactive object) ની પ્રોપર્ટી તરીકે એક્સેસ કરવામાં આવે ત્યારે તે લાગુ પડતું નથી.
એરે (Arrays) અને કલેક્શનમાં ચેતવણી
રિએક્ટિવ ઓબ્જેક્ટ્સથી વિપરીત, જ્યારે રિફને રિએક્ટિવ એરેના એલિમેન્ટ અથવા Map જેવી મૂળ કલેક્શન ટાઈપ તરીકે એક્સેસ કરવામાં આવે ત્યારે કોઈ અનવ્રેપિંગ કરવામાં આવતું નથી:
js
const books = reactive([ref('Vue 3 Guide')])
// અહીં .value ની જરૂર છે
console.log(books[0].value)
const map = reactive(new Map([['count', ref(0)]]))
// અહીં .value ની જરૂર છે
console.log(map.get('count').value)ટેમ્પલેટ્સમાં અનવ્રેપિંગ કરતી વખતે ચેતવણી
ટેમ્પલેટ્સમાં રિફ અનવ્રેપિંગ ફક્ત ત્યારે જ લાગુ થાય છે જો રિફ ટેમ્પલેટ રેન્ડર કોન્ટેક્સ્ટમાં ટોપ-લેવલ પ્રોપર્ટી હોય.
નીચેના ઉદાહરણમાં, count અને object ટોપ-લેવલ પ્રોપર્ટીઝ છે, પરંતુ object.id નથી:
js
const count = ref(0)
const object = { id: ref(1) }તેથી, આ એક્સપ્રેશન અપેક્ષા મુજબ કામ કરે છે:
template
{{ count + 1 }}...જ્યારે આ કામ કરતું નથી:
template
{{ object.id + 1 }}રેન્ડર કરેલ પરિણામ [object Object]1 હશે કારણ કે એક્સપ્રેશનના મૂલ્યાંકન વખતે object.id અનવ્રેપ થયેલું નથી અને તે રિફ ઓબ્જેક્ટ રહે છે. આને ઠીક કરવા માટે, અમે id ને ટોપ-લેવલ પ્રોપર્ટીમાં ડિસ્ટ્રક્ચર કરી શકીએ છીએ:
js
const { id } = objecttemplate
{{ id + 1 }}હવે રેન્ડર પરિણામ 2 હશે.
બીજી નોંધવા જેવી બાબત એ છે કે રિફ અનવ્રેપ થઈ જાય છે જો તે ટેક્સ્ટ ઇન્ટરપોલેશનનું અંતિમ મૂલ્યાંકન કરેલ મૂલ્ય હોય (એટલે કે {{ }} ટેગ), તેથી નીચે આપેલ 1 રેન્ડર થશે:
template
{{ object.id }}આ ફક્ત ટેક્સ્ટ ઇન્ટરપોલેશનની સગવડતા છે અને તે {{ object.id.value }} ની સમકક્ષ છે.