Bài 11: Cách sử dụng forceUpdate trong VueJS
Mình đã cập nhật lại tất cả các bài với các thay đổi ở hiện tại ở năm 2024: Vue 3, Vite, Laravel 11x,...
Cập nhật gần nhất: 08/06/2024
Chào mừng các bạn quay trở lại với series học VueJS của mình, ở bài trước ta đã tìm hiểu về vòng đời của Vue instance, và bài này sẽ giới thiệu cho các bạn về các re-render lại DOM khi cần thiết, và các lỗi liên quan. Mình tổng hợp dựa vào những gì mình học được trong quá trình phát triển ứng dụng.
forceUpdate là gì? 🤔
forceUpdate
là một phương pháp mà bạn có thể sử dụng để buộc một component Vue cập nhật lại mà không cần phải thay đổi dữ liệu hoặc trạng thái của nó. Điều này có thể hữu ích trong một số tình huống, nhưng cần được sử dụng cẩn thận.
Cách sử dụng forceUpdate
Trong Vue 3, bạn có thể sử dụng forceUpdate
từ API toàn cục (global) của Vue. Dưới đây là một ví dụ:
<template>
<div>
<p>{{ message }} - {{ count }}</p>
<button @click="updateMessage">Update Message</button>
<button @click="updateCount">Update Count</button>
<button @click="forceUpdateComponent">Force Update</button>
</div>
</template>
<script setup>
import { ref, getCurrentInstance } from 'vue';
const message = ref('Hello, World!');
const { proxy } = getCurrentInstance();
let count = 1
function updateMessage() {
message.value = 'Hello, Vue 3!';
}
function updateCount() {
count++
}
function forceUpdateComponent() {
proxy.$forceUpdate();
}
</script>
Khi chạy lên ta có UI như sau:
Khi bấm Update Message
thì ta thấy ngay lập tức message đã thay đổi trên màn hình. Nhưng khi bấm Update Count
thì không có gì xảy ra cả.
Lí do là bởi vì ta đang khai báo count
chỉ là 1 biến JS thường, nên với Vue nó không phải là reactive state
, tức là Vue sẽ không theo dõi khi giá trị của count
thay đổi.
Tiếp theo nếu ta bấm Force Update
thì sẽ thấy là giá trị của count
trên màn hình sẽ được cập nhật.
Giờ nếu ta F5 lại trình duyệt -> Update Count
-> Update Message
thì cũng thấy giá trị của count
thay đổi trên UI, lí do là vì khi ta Update Message
thì Vue sẽ tiến hành re-render bởi vì message
là reactive state
, và count
cũng được "ăn hôi" và thay đổi theo 😂😂
Ở Vue 2 cách dùng là gọi:
this.$forceUpdate()
ở bất kì đâu trong component
Khi Nào Nên Dùng forceUpdate
? ⏰
forceUpdate
nên được sử dụng trong các tình huống sau:
- Khi bạn cần cập nhật giao diện mà không có thay đổi dữ liệu rõ ràng.
- Khi bạn tích hợp với các thư viện bên thứ ba mà không trigger reactivity của Vue.
- Khi bạn thực hiện các thao tác DOM phức tạp và cần đảm bảo giao diện luôn cập nhật.
Tại Sao Nên Hạn Chế Dùng forceUpdate
? ⚠️
Mặc dù forceUpdate
có thể hữu ích trong một số tình huống, nhưng nó cũng có những hạn chế và có thể gây ra các vấn đề sau:
- Hiệu suất:
forceUpdate
lại toàn bộ component có thể làm giảm hiệu suất, đặc biệt là khi component phức tạp. - Khó bảo trì: Sử dụng
forceUpdate
có thể làm cho code của bạn khó hiểu và khó bảo trì hơn. Điều này đặc biệt đúng khi nhiều developer làm việc trên cùng một dự án. - Thiếu minh bạch:
forceUpdate
bỏ qua hệ thống reactivity của Vue, làm mất đi tính minh bạch và dễ hiểu của ứng dụng.
Kết luận
Bài này siêu ngắn 😂
Hiểu rõ và sử dụng forceUpdate
một cách cẩn thận có thể giúp bạn giải quyết một số vấn đề phức tạp trong ứng dụng Vue 3 của mình. Tuy nhiên, hãy luôn nhớ rằng việc lạm dụng forceUpdate
có thể dẫn đến các vấn đề về hiệu suất và bảo trì. Luôn ưu tiên sử dụng các phương pháp reactivity tiêu chuẩn của Vue trước khi nghĩ đến forceUpdate
.
Mong rằng các bạn đã hiểu được cách $forceUpdate
hoạt động, qua đó sử dụng một cách đúng đắn tránh được các trường hợp không hiểu vì sao hiển thị dữ liệu không đúng, hoặc những trường hợp thôi cứ thêm vào forceUpdate cho nó chắc
.
Nói chung khi code mình hạn chế sử dụng $forceUpdate
, với mình đó là giải pháp tệ nhất khi không giải thích được lỗi về data. Như trang chủ Vue đã khuyến cáo:
If you find yourself needing to force an update in Vue, in 99.99% of cases, you’ve made a mistake somewhere.
Tạm dịch:
Nếu bạn thấy mình cần phải sử dụng forceUpdate, thì 99% là bạn đã phạm sai lầm ở đâu đó rồi :-D
Hôm nay viết nhiều buồn ngủ quá rồi. Hẹn gặp lại các bạn vào bài tới với cách binding class và style
cho các thẻ HTML. Có gì thắc mắc các bạn comment bên dưới nhé ^^!
All rights reserved
Bình luận
Vue.set(this.person, 'nickname', 'Louis'); Em hiểu như này đúng k a theo từng giá trị trong vue set từ trái qua phải, giá trị đầu là đối tượng cần trỏ đến, giá trị 2 là thuộc tính của đối tượng, giá trị 3 là value cần set cho thuộc tính ở giá trị 2
đúng rồi em
Thêm import Vue from 'vue' trong tag <script>, nếu các bạn sử dụng VueCLI nhé
bài viết này e thấy 2 ví dụ này giống nhau đấy bác. e gà quá. đọc xong bài viết này không thấy hiểu gì
(
nếu không hiểu chỗ nào bạn comment cho mình đc biết nhé
Tại hàm changeNicknameProperly() -> Vue.set( ... ) đổi thành this.$set ( ... ) mới hoạt động.
E đang theo hương lập trình laravel + vuejs, nhưng quá nhiều thứ không biết, nếu có thể add skype live:20ceee01d0a0fe39 , hi vọng nhận được nhiều sự hỗ trợ từ anh.
oke bạn nhé mình add rồi, nếu có gì giúp đc thì ae cùng phát triển
Em thử lần đầu ấn button "Change Nick Name" sau đó ấn button "Change NIck name properly" rồi quay lại ấn button "Change Nick Name" tại sao nick name vẫn không hiển thị trên web vậy anh?
Chào em, khi lần đầu e bấm
Change Nick Name
khi đónickname
sẽ không reactive, Vue sẽ "không để ý" tới sự thay đổi giá trị của thằng đó, tiếp theo em bấmChange NIck name properly
, dù cóVue.set
, nhưng thực chất ở đây e chỉ thay đổi giá trị thằngnickname
vừa được tạo ra trước đó, mà thằng này không reactive nên Vue sẽ không "quan tâm" và không re-render lại nữa, đó là lí do e không thấy có thay đổi trên màn hình, dù em bấm thế nào đi chăng nữa. Trừ khi em bấm buttonChange Name
khi đó thằngname
thay đổi (vì nó được khai báo ởdata
nên sẽ reactive) ->Vue re-render ->nickname
cũng được re-renderRút ra: chỉ cần từ ban đầu em bấm
Change Nick Name
là từ đónickname
đã bị coi như khôngreactive
rồi và em sẽ phải dùngforceUpdate
từ giờ về sau nếu muốn Vue re-render để thấy thay đổi trên màn hình. Do đó, đểnickname
là reactive, thì ngay từ ban đầu e phải gọiVue.set
trước, sau đó thì e bấmChange Nick Name
thoải mái sẽ thấynickname
liên tục thay đổi.Em cảm ơn anh nhiều ạ
Khá clean good post
Hello anh, lại là em đây, một fan của anh
. Nay em đã đi thực tập và đang chiến đấu ở vị trí frontend dev (vuejs). Tuy nhiên nay em có gặp một trường hợp tuy đã tìm ra lời giải nhưng em không thể biết được nguyên nhân và cách làm của mình đã tối ưu hay chưa. Giờ muốn hỏi anh ạ.
Cụ thể là em sẽ có 2 component cha con giao tiếp với nhau, nhưng vì một lí do nào đó (mà em không biết
) thì dữ liệu nó không reactive theo ý em muốn và nó chỉ hoạt động như em mô tả dưới hình ạ.

Và sau một hồi loay hoay thì cách khắc phục của em đó là bind thằng "key" vào thằng con, mỗi khi thằng cha thay đổi -> random ra một key -> thằng component con render lại. Vậy em muốn hỏi là liệu cách làm vậy có đúng và nguyên nhân của việc data trong thằng con k reactive ạ. Em cảm ơn.
Chào e,
Đây là 1 điều ở trong docs của Vue đã nói tới nhé e, gọi là One Way Data flow. Data truyền từ cha xuống con thông qua
props
, thì nó sẽ chỉchảy
(flow) từ cha xuống, chứ không chảy cả theo chiều ngược lại, điều này tránh việc emutate
trực tiếp props ở con, làm data ở cha thay đổi (mà không quaemit
).Do với ở bài của e, e truyền vào như kia thì chúng chỉ làm giá trị khởi đầu cho con thôi, kể từ sau thì props thay đổi data của con sẽ ko reactive nữa
Thế tại sao
this.heySon
vẫn reactive??Ở ngay trong docs kia có note luôn rằng: nếu e truyền array hoặc object từ cha vào con thì vì chúng được truyền xuống bằng địa chỉ (reference), nên cha thay đổi sẽ thấy con reactive ngay, hay nói cách khác, ở đây con có thể thay đổi trực tiếp props dẫn tới
data
ở phía cha cũng bị thay đổi theo --->> Flow của app bắt đầu bị rối rắmDo đó a đoán là
heySon
của e ở cha đang là object hoặc array nên sẽ được truyền xuống con bằng địa chỉ (pass-by-reference) cònheyNeighbor
đang là number, string hoặc boolean (truyền xuống bằng giá trị, pass-by-value, sẽ không reactive theo cha)Giải pháp cho việc này
Việc
).
heySon
đang bị truyền vào bằng địa chỉ như kia sẽ làm cho con có thể thay đổi trực tiếp props mà không thông quaemit
. Đồng thời a hiểu ý định của e là "truyền props trực tiếp vào data của con, để khi props thay đổi thì data của con cũng reactive theo", nhưng điều này vô hình chung sẽ làm flow của app sẽ rối, không đúng với tư tưởng của Vue làprops down, event up
(ý là data từ cha xuống con thì qua props, còn con lên cha thì quaemit
) và hậu quả là dễ sinh ra lỗi (như lỗi e đang gặp phải vậyCách giải quyết a thường chọn là ở con, e
watch
props từ cha hoặc dùngcomputed
rồi update vàodata
của con. Demo:Ở trên thì
foot
vàhands
sẽ reactive theo props từ cha, nhưng khi e bindfoot
vàhands
và khi giá trị của chúng thay đổi từ phía con thì data sẽ không tự truyền lại cha, mà e cần phải dùngemit
để đồng bộ (nếu e cần thiết điều đó)Chú ý nữa rằng ở con nếu e thay đổi trực tiếp giá trị của 1 thuộc tính của
heySon
(nested props) thì sẽ không thấy báo lỗiAvoid mutating a prop directly
-ko đc thay đổi props
, mặc dù thực tế ta đang thay đổi giá trị thuộc tính của nó. Đây là 1 vấn đề đã đc Evan giải thích ở đây. Mặc dù đây ko phải là lỗi nhưng vẫn ko khuyến khích dùng cách này. Cứ muốn thay đổi data của cha thì luôn dùngemit
nhé e.@maitrungduc1410 Dạ em đã hiểu ạ, cảm ơn anh nhiều.