Optional Chaining trong template Vuejs để tránh xảy ra lỗi?
- Tram Ho
Tại sao cần sử dụng
Khi chúng ta muốn hiển thị giá trị trong object ra template
1 2 3 4 | <span class="token tag"><span class="token punctuation"><</span>template<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>p<span class="token punctuation">></span></span>{{ data.user.name }}<span class="token tag"><span class="token punctuation"></</span>p<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"></</span>template<span class="token punctuation">></span></span> |
Trong trường hợp này nếu thuộc tính user
không tồn tại, trình duyệt sẽ báo lỗi
1 2 | Error in render: "TypeError: Cannot read property 'name' of undefined" |
Và nó có thể khiến cho một một số component của thư viện UI không hiển thị, vậy nên có một cách đó là check if trước khi hiển thị
1 2 3 4 | <span class="token tag"><span class="token punctuation"><</span>template<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>p<span class="token punctuation">></span></span>{{ data.user && data.user.name }}<span class="token tag"><span class="token punctuation"></</span>p<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"></</span>template<span class="token punctuation">></span></span> |
Nhưng mỗi lần phải check như vậy đối với các thuộc tính được lồng trong nhiều object thì nó sẽ trở thành như này
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token tag"><span class="token punctuation"><</span>template<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>p<span class="token punctuation">></span></span> {{ data.obj1 && data.obj1.obj2 && data.obj1.obj2.obj3 && data.obj1.obj2.obj3.obj4 ... }} <span class="token tag"><span class="token punctuation"></</span>p<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"></</span>template<span class="token punctuation">></span></span> |
Rất dài dòng và mệt mỏi
Optional chaining là gì
Được giới thiệu trong ES2020 của javascript, optional chaining ?.
giúp cho việc truy cập đến các phần tử trong object ngay cả khi object không tồn tại
Có 3 kiểu cú pháp trong đấy 2 kiểu gọi đến phần tử và 1 kiểu gọi đến phương thức trong object
1 2 3 4 | data<span class="token operator">?.</span>obj data<span class="token operator">?.</span><span class="token punctuation">[</span>obj<span class="token punctuation">]</span> data<span class="token punctuation">.</span>method<span class="token operator">?.</span><span class="token punctuation">(</span><span class="token punctuation">)</span> |
Hiện tại optional chaining mới chỉ được hỗ trợ trên template của Vue 3, còn Vue 2 khi sử dụng sẽ báo lỗi
1 2 | SyntaxError: Unexpected token |
Nên mình sẽ hướng dẫn cách cài đặt để có thể sử dụng optional chaining trên template của Vue 2
Cài đặt biên dịch
Sử dụng thư viện vue-template-babel-compiler
để biên dịch
Chạy lệnh để cài đặt
1 2 | yarn add -D vue-template-babel-compiler |
Cấu hình tại vue.config.js
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token comment">// vue.config.js</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token function-variable function">chainWebpack</span><span class="token operator">:</span> <span class="token parameter">config</span> <span class="token operator">=></span> <span class="token punctuation">{</span> config<span class="token punctuation">.</span>module <span class="token punctuation">.</span><span class="token function">rule</span><span class="token punctuation">(</span><span class="token string">'vue'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token string">'vue-loader'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">tap</span><span class="token punctuation">(</span><span class="token parameter">options</span> <span class="token operator">=></span> <span class="token punctuation">{</span> options<span class="token punctuation">.</span>compiler <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'vue-template-babel-compiler'</span><span class="token punctuation">)</span> <span class="token keyword">return</span> options <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Hoặc nếu sử dụng webpack để biên dịch vue
1 2 3 4 5 6 7 8 9 10 11 12 13 | <span class="token comment">// webpack.config.js</span> module<span class="token operator">:</span> <span class="token punctuation">{</span> rules<span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> test<span class="token operator">:</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\.vue$</span><span class="token regex-delimiter">/</span></span><span class="token punctuation">,</span> loader<span class="token operator">:</span> <span class="token string">"vue-loader"</span><span class="token punctuation">,</span> options<span class="token operator">:</span> <span class="token punctuation">{</span> compiler<span class="token operator">:</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"vue-template-babel-compiler"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> |
Với trường hợp sử dụng Unit test với Jest cũng cần phải cấu hình để có thể biên dịch được trên môi trường test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token comment">// jest.config.js</span> module<span class="token punctuation">.</span>exports <span class="token operator">=</span> <span class="token punctuation">{</span> transform<span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string">'.*\\.(vue)$'</span><span class="token operator">:</span> <span class="token string">'vue-jest'</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> globals<span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string">'vue-jest'</span><span class="token operator">:</span> <span class="token punctuation">{</span> templateCompiler<span class="token operator">:</span> <span class="token punctuation">{</span> compiler<span class="token operator">:</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'vue-template-babel-compiler'</span><span class="token punctuation">)</span><span class="token punctuation">,</span> transformAssetUrls<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> |
Lưu ý: phiên bản của vue-jest phải lớn hơn hoặc bằng 4.0.0 và jest nhỏ hơn hoặc bằng 26.6.3.
Sử dụng với template
Và bây giờ chúng ta chỉ cần viết thế này là trình duyệt không báo lỗi khi Error in render: "TypeError: Cannot read property 'name' of undefined"
nữa
1 2 3 4 | <span class="token tag"><span class="token punctuation"><</span>template<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>p<span class="token punctuation">></span></span>{{ data?.user?.name }}<span class="token tag"><span class="token punctuation"></</span>p<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"></</span>template<span class="token punctuation">></span></span> |
Nhưng trên màn hình lúc này thẻ p sẽ render ra undefined
Có một cách mọi người thường dùng là kết hợp với nullish coalescing operator
để hiển thị ra giá trị rỗng thay vì undefined
1 2 3 4 | <span class="token tag"><span class="token punctuation"><</span>template<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>p<span class="token punctuation">></span></span>{{ data?.user?.name ?? '' }}<span class="token tag"><span class="token punctuation"></</span>p<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"></</span>template<span class="token punctuation">></span></span> |
Cách hay hơn là sử dụng v-text
, nó sẽ kiểm tra giá thị rồi mới render ra thẻ p còn không thì sẽ không render, một directive rất hay nhưng lại bị rất nhiều người bỏ qua
1 2 3 4 | <span class="token tag"><span class="token punctuation"><</span>template<span class="token punctuation">></span></span> <span class="token tag"><span class="token punctuation"><</span>p <span class="token attr-name">v-text</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>data?.user?.name<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span> <span class="token tag"><span class="token punctuation"></</span>template<span class="token punctuation">></span></span> |
Sự kết hợp hoàn hảo