
Posted on • Originally published atblog.soards.me
Quick Tip: Breaking Vue's Reactivity
VueJS is my front-end framework of choice. I use it at work and on various side projects. I love Vue's opt-in style reactivity engine (as opposed to React's opt-out style), but on occasion I find myself needing to purposelybreak the reactivity of a value.
One such situation that I have run into on multiple occasions recently is when using a confirmation dialog. It's a good practice when deleting an object through a UI, to not immediately perform the delete on the initial click, but to firstconfirm the destructive action with the user. That's becausepreventing errors is better than helping users recover from them. This principle is #5: Error Prevention on Jakob Nielson's10 Usability Heuristics for User Interface Design
Let's say I have an object from a list selected and I click Delete. To confirm this action, I show a dialog that display's the selected object's name along with a question asking if the user is sure they want to delete it.
To accomplish this, I save the selected object to aref
calledselectedObj
and I useselectedObj.value.name
in the text of the confirmation.
If the user clicks "Yes, Delete", we fire off a delete request, resetselectedObj
toundefined
, and close the dialog.
But becauseselectedObj
is a reactive ref, as the dialog is fading out thename will disappear and the remaining text will shift suddenly, which is apretty janky UX.
constselectedObj=ref();constisConfirmOpen=ref(false);asyncfunctiondeleteObject(){if(selectedObj.value?.id===undefined)return;awaithttp.delete(`/api/item/${selectedObj.value.id}`);selectedObj.value=undefined;isConfirmOpen.value=false;}
The simple solution is tomake a non-reactive copy of the name before opening the dialog. Since the name value is a string, we can just copy it to alet
and use that in the dialog's text.
letconfirmObjName='';functionhandleDeleteObject(){// make a copy of the preset name before opening the confirm modalconfirmObjName=selectedObj.value?.name??'';isConfirmOpen.value=true;}
<!-- button with click handler --><buttontype="button"@click="handleDeleteObject">Delete Object</button>
<!-- modal component --><DModalv-model:open="isConfirmOpen"@confirm="deleteObject"><p> Are you sure you want to delete<spanclass="font-semibold">{{ confirmObjName }}</span>? This action cannot be undone.</p></DModal>
If we needed to break reactivity of the entireselectedObj
we could copy it using Vue'stoRaw
method.
letselectedObjCopy=toRaw(selectedObj.value);
However, this is not necessary if all we are copying is a primitive value like a string.
Now when I setselectedObj
toundefined
after sending the delete request,the name of the object will no longer disappear before the dialog closes.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse