<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="https://publishpress.com/"
	>

<channel>
	<title>Javascript Archives - Tomoshare</title>
	<atom:link href="https://blog.tomosia.com.vn/danh-muc/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.tomosia.com.vn/danh-muc/javascript/</link>
	<description>Kênh chia sẻ kiến thức Tomosia Việt Nam</description>
	<lastBuildDate>Wed, 03 Jan 2024 08:43:51 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://blog.tomosia.com.vn/wp-content/uploads/2023/09/cropped-icon-32x32.png</url>
	<title>Javascript Archives - Tomoshare</title>
	<link>https://blog.tomosia.com.vn/danh-muc/javascript/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Authentication Google with NextJS and NextAuth</title>
		<link>https://blog.tomosia.com.vn/authentication-google-with-nextjs-and-nextauth/</link>
					<comments>https://blog.tomosia.com.vn/authentication-google-with-nextjs-and-nextauth/#comments</comments>
		
		<dc:creator><![CDATA[admin_tomosia]]></dc:creator>
		<pubDate>Wed, 03 Jan 2024 08:02:37 +0000</pubDate>
				<category><![CDATA[Security]]></category>
		<category><![CDATA[ReactJS]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=3007</guid>

					<description><![CDATA[<p>Authentication Hướng dẫn này trình bày quy trình đơn giản trong việc kết hợp xác thực vào ứng&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/authentication-google-with-nextjs-and-nextauth/">Authentication Google with NextJS and NextAuth</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Authentication</p>



<p class="wp-block-paragraph">Hướng dẫn này trình bày quy trình đơn giản trong việc kết hợp xác thực vào ứng dụng Next.js của bạn bằng thư viện next-auth. Mặc dù thư viện cung cấp nhiều tùy chọn (nhà cung cấp), hướng dẫn này tập trung vào việc triển khai bằng cách sử dụng Nhà cung cấp Google.</p>



<p class="wp-block-paragraph">Về hướng dẫn này, mọi người cũng sẽ hiểu rõ hơn về việc dễ dàng thiết lập các tuyến được bảo vệ trong ứng dụng của mình, một nhiệm vụ được thư viện next-auth này thực hiện dễ dàng.</p>



<p class="wp-block-paragraph"></p>



<h4 id="thiet-lap-thu-vien-next-auth" class="wp-block-heading">Thiết lập thư viện next-auth</h4>



<p class="wp-block-paragraph">Đầu tiên mọi người phải có 1 chiếc project nextjs đã, mọi người có thể tham khảo hướng dẫn trên trang chủ của Nextjs tại đây, hướng dẫn quá chi tiết: <a href="https://nextjs.org/docs/getting-started/installation">https://nextjs.org/docs/getting-started/installation</a></p>



<p class="wp-block-paragraph">Cài đặt thư viện next-auth bằng lệnh sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Bash</span><span role="button" tabindex="0" data-code="npm install next-auth" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #62E884">npm</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">install</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">next-auth</span></span></code></pre></div>



<p class="wp-block-paragraph">Sau khi hoàn tất cài đặt, hãy tạo thư mục api trong thư mục ứng dụng gốc và bên trong thư mục đó tạo thư mục /auth. Cuối cùng, tạo thư mục [&#8230;nextauth] bên trong thư mục auth đó.</p>



<p class="wp-block-paragraph">Inside the&nbsp;<code>[...nextauth]</code>&nbsp;folder, create two files named&nbsp;<code>route.ts</code>&nbsp;and&nbsp;<code>options.ts</code>.</p>



<p class="wp-block-paragraph">Cấu trúc thư mục của mọi người cho đến thời điểm này sẽ trông như thế này:</p>



<figure class="wp-block-image size-full is-resized"><img fetchpriority="high" decoding="async" width="412" height="270" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-15.51.15.png" alt="" class="wp-image-3019" style="width:680px;height:auto" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-15.51.15.png 412w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-15.51.15-300x197.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-15.51.15-380x249.png 380w" sizes="(max-width: 412px) 100vw, 412px" /></figure>



<p class="wp-block-paragraph">Sau đó, trong tệp options.ts, chèn đoạn mã sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">TypeScript</span><span role="button" tabindex="0" data-code="import type { NextAuthOptions } from 'next-auth'
import GoogleProvider from &quot;next-auth/providers/google&quot;;

export const options: NextAuthOptions = {
    providers: [
  GoogleProvider({
    clientId: process.env.GOOGLE_CLIENT_ID as string,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
  })
]
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">type</span><span style="color: #F6F6F4"> { NextAuthOptions } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">next-auth</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> GoogleProvider </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">next-auth/providers/google</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> options</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">NextAuthOptions</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    providers</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> [</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">GoogleProvider</span><span style="color: #F6F6F4">({</span></span>
<span class="line"><span style="color: #F6F6F4">    clientId</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> process.env.</span><span style="color: #BF9EEE">GOOGLE_CLIENT_ID</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">as</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">string</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">    clientSecret</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> process.env.</span><span style="color: #BF9EEE">GOOGLE_CLIENT_SECRET</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">as</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">string</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  })</span></span>
<span class="line"><span style="color: #F6F6F4">]</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<p class="wp-block-paragraph">việc bạn có thể thêm nhiều Provider khác sử dụng mạng xã hội các bạn có thể tham khảo tại đây, có hướng dẫn cụ thể như đoạn code <mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-cyan-bluish-gray-color"><code>GoogleProvider</code></mark> trên</p>



<p class="wp-block-paragraph">Biến <code>options</code> là nơi chúng ta nhúng bất kỳ nhà cung cấp nào chúng tôi dự định sử dụng từ next-auth</p>



<p class="wp-block-paragraph">Để sử dụng đăng nhập bằng Google một cách hiệu quả, mọi người cần có các thuộc tính clientId và clientSecret của mình. Hãy yên tâm, mình sẽ sớm đi sâu vào vấn đề này. Đầu tiên, tạo tệp .env nơi bạn sẽ gán giá trị cho cả hai thuộc tính đã khai báo bên trên.</p>



<p class="wp-block-paragraph"><strong>lưu ý rằng tạo file .env nên đặt nó ở thư mục gốc để tránh các lỗi có thể sảy ra nếu như không config nó ở trong file config</strong></p>



<p class="wp-block-paragraph">OK giờ chúng ta cùng đi đến bước setup Google nào!!!</p>



<h3 id="setup-google" class="wp-block-heading">Setup google</h3>



<p class="wp-block-paragraph">Truy cập trang <a href="https://cloud.google.com/">https://cloud.google.com/</a> và tiến hành tạo mới một project trên đó</p>



<p class="wp-block-paragraph">Mình sẽ bỏ qua bước tạo project vì hầu như trên mạng cũng đã có rồi, mà mình sẽ hướng dẫn từ bước mọi người đã tạo xong nhé</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="488" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/console-1024x488.png" alt="" class="wp-image-3020" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/01/console-1024x488.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/console-300x143.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/console-768x366.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/console-380x181.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/console-800x381.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/console-1160x553.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/console.png 1366w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Sau khi tạo xong các bạn sẽ được tới 1 trang như thế này, bấm theo các bước mình đã chụp ở trên, đầu tiên chọn Credentials</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="488" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/configure-1024x488.png" alt="" class="wp-image-3021" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/01/configure-1024x488.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/configure-300x143.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/configure-768x366.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/configure-380x181.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/configure-800x381.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/configure-1160x553.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/configure.png 1366w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Sau đó ở màn hình Credentials nhấn chọn button &#8220;CONFIGURE CONSENT SCREEN&#8221;</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="488" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/external-1024x488.png" alt="" class="wp-image-3022" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/01/external-1024x488.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/external-300x143.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/external-768x366.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/external-380x181.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/external-800x381.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/external-1160x553.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/external.png 1366w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Sau khi đã thiết lập cũng như đồng ý các điều khoản thì mọi người sẽ được chuyển tới màn hình như sau:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="488" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/oauth-1024x488.png" alt="" class="wp-image-3023" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/01/oauth-1024x488.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/oauth-300x143.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/oauth-768x366.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/oauth-380x181.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/oauth-800x381.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/oauth-1160x553.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/oauth.png 1366w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">ở màn hình này chúng ta sẽ chả làm gì cả vì cũng chưa setup gì cho project của mình, chuyển tiếp về lại trang Credentials:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1000" height="476" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/create-id.gif" alt="" class="wp-image-3024"/></figure>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="1000" height="476" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/application.gif" alt="" class="wp-image-3025" style="width:680px;height:auto"/></figure>



<p class="wp-block-paragraph">nhập các thông tin đầy đủ vào phần Create OAuth client ID:</p>



<p class="wp-block-paragraph">Cuộn xuống phần &#8220;Authorize redirect URI&#8221; và dán URI sau:<br>http://localhost:3000/api/auth/callback/google. Sau đó bấm nút Create</p>



<p class="wp-block-paragraph">Trong trường hợp mọi người muốn setup cho production thì thay vì để localhost hãy thay bằng domain của mình</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="488" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/id-1024x488.png" alt="" class="wp-image-3026" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/01/id-1024x488.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/id-300x143.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/id-768x366.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/id-380x181.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/id-800x381.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/id-1160x553.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/id.png 1366w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Cuối cùng thì id của chúng ta cần đã xuất hiện, việc chúng ta cần làm là đưa 2 id này vào trong phần .env của dự án mình và tiến hành tới bước tiếp theo, test</p>



<p class="wp-block-paragraph">Mọi người cũng cần tạo key NEXT_AUTH_SECRET để tăng cường tính bảo mật của quy trình xác thực trong next-auth. Mình từng mắc tới việc nếu không thêm key này thì không thể sử dụng tới Google được nên mọi người cứ thêm vào cho chắc nhé. Tạo secret key của mọi người bằng cách thực hiện lệnh sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Bash</span><span role="button" tabindex="0" data-code="openssl rand -base64 32" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #62E884">openssl</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">rand</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">-base64</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">32</span></span></code></pre></div>



<p class="wp-block-paragraph">Lệnh này sẽ tạo ra một chuỗi 32 ký tự. Sao chép chuỗi này và dán nó làm giá trị cho biến NEXTAUTH_SECRET trong tệp .env này. Tệp .env cuối cùng của chúng ta sẽ giống như sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">Bash</span><span role="button" tabindex="0" data-code="GOOGLE_CLIENT_ID = client ID value
GOOGLE_CLIENT_SECRET = client secret value
NEXT_AUTH_SECRET = next auth secret" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #62E884">GOOGLE_CLIENT_ID</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">=</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">client</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">ID</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">value</span></span>
<span class="line"><span style="color: #62E884">GOOGLE_CLIENT_SECRET</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">=</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">client</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">secret</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">value</span></span>
<span class="line"><span style="color: #62E884">NEXT_AUTH_SECRET</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">=</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">next</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">auth</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">secret</span></span></code></pre></div>



<p class="wp-block-paragraph">Sau khi bạn đã triển khai thành công các biến .env, hãy dán đoạn mã sau vào tệp Route.ts của mình:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">TypeScript</span><span role="button" tabindex="0" data-code="import NextAuth from &quot;next-auth/next&quot;;
import { options } from &quot;./options&quot;;

const handler = NextAuth(options);

export { handler as GET, handler as POST };" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> NextAuth </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">next-auth/next</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> { options } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">./options</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> handler </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">NextAuth</span><span style="color: #F6F6F4">(options);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> { handler </span><span style="color: #F286C4">as</span><span style="color: #F6F6F4"> GET, handler </span><span style="color: #F286C4">as</span><span style="color: #F6F6F4"> POST };</span></span></code></pre></div>



<p class="wp-block-paragraph">Điều này đảm bảo rằng các request GET và POST được gửi đến điểm cuối này api/auth/[&#8230;nextauth] sẽ được thư viện next-auth xử lý.</p>



<p class="wp-block-paragraph">Cuối cùng, hãy khởi động lại ứng dụng nextjs của chúng ta. Điều quan trọng cần lưu ý là thư viện next-auth sẽ không hoạt động ngay vào thời điểm này. Lý do là chúng ta vẫn chưa triển khai protected routes để bảo vệ các trang của mình. Chúng ta sẽ khám phá khía cạnh này tiếp theo.</p>



<h3 id="lam-sao-de-implement-protected-routes-voi-next-auth" class="wp-block-heading">Làm sao để implement Protected Routes với <code>next-auth</code></h3>



<p class="wp-block-paragraph">Với việc sử dụng middleware của Next.js, việc bảo vệ các routes trở nên rất dễ dàng.</p>



<p class="wp-block-paragraph">Bắt đầu bằng cách tạo tệp middleware.ts trong thư mục src gốc.</p>



<p class="wp-block-paragraph">Để bảo vệ tất cả các trang của bạn một cách thống nhất, hãy chèn đoạn mã sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">TypeScript</span><span role="button" tabindex="0" data-code="export { default } from 'next-auth/middleware'" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> { </span><span style="color: #F286C4">default</span><span style="color: #F6F6F4"> } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">next-auth/middleware</span><span style="color: #DEE492">&#39;</span></span></code></pre></div>



<p class="wp-block-paragraph">Ngoài ra, mọi người có thể bảo mật riêng các trang cụ thể bằng cách sử dụng <code>matcher</code>. Ví dụ: chỉ bảo vệ trang chủ và cart sẽ được triển khai như sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">TypeScript</span><span role="button" tabindex="0" data-code="export { default } from 'next-auth/middleware'

export const config = { matcher: ['/', '/cart'] }" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> { </span><span style="color: #F286C4">default</span><span style="color: #F6F6F4"> } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">next-auth/middleware</span><span style="color: #DEE492">&#39;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> config </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> { matcher</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> [</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">/</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">/cart</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">] }</span></span></code></pre></div>



<p class="wp-block-paragraph">Bây giờ, khi ta truy cập cả hai trang trên localhost của mình, chúng sẽ hiển thị lời nhắc xác thực mời bạn &#8220;Sign in with Google&#8221; thay vì hiển thị nội dung thông thường:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="488" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/sign-in-1024x488.png" alt="" class="wp-image-3029" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/01/sign-in-1024x488.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/sign-in-300x143.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/sign-in-768x366.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/sign-in-380x181.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/sign-in-800x381.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/sign-in-1160x553.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/sign-in.png 1366w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 id="tong-ket-lai" class="wp-block-heading">Tổng kết lại</h3>



<p class="wp-block-paragraph">Trong hướng dẫn này, mình đã đề cập đến các bước cần thiết để triển khai authenticate và được protected trong ứng dụng Next.js của bạn bằng thư viện next-auth với Nhà cung cấp Google.</p>



<p class="wp-block-paragraph">Với kiến ​​thức thu được ở đây, giờ đây mọi người có thể tự tin phát triển các ứng dụng cung cấp khả năng kiểm soát truy cập an toàn và nội dung được cá nhân hóa dựa trên xác thực người dùng.</p>



<p class="wp-block-paragraph">Mọi người cũng có thể triển khai thêm trên các mạng xã hội khác, ví dụ như Facebook, Instagram, Apple, &#8230;</p>



<p class="wp-block-paragraph">Mọi người có thể truy cập vào đây để có thể triển khai những nhà cung cấp khác nhé <a href="https://next-auth.js.org/providers/">https://next-auth.js.org/providers/</a></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="396" height="1024" src="http://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-16.33.39-396x1024.png" alt="" class="wp-image-3030" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-16.33.39-396x1024.png 396w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-16.33.39-116x300.png 116w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-16.33.39-594x1536.png 594w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-16.33.39-380x982.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2024/01/Screen-Shot-2024-01-02-at-16.33.39.png 596w" sizes="auto, (max-width: 396px) 100vw, 396px" /></figure>



<p class="wp-block-paragraph">có hàng ti tỉ thứ nằm ở đây chờ đón mọi người đó ^^</p>



<p class="wp-block-paragraph">Sắp tới mình sẽ ra thêm nhiều blog liên quan tới Frontend hơn nữa, sẽ chi tiết hơn nên mọi người nhớ đón chờ nhé</p>
<p>The post <a href="https://blog.tomosia.com.vn/authentication-google-with-nextjs-and-nextauth/">Authentication Google with NextJS and NextAuth</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/authentication-google-with-nextjs-and-nextauth/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Storybook là gì? Cách sử dụng storybook trong Reactjs</title>
		<link>https://blog.tomosia.com.vn/storybook-la-gi-cach-su-dung-storybook-trong-reactjs/</link>
					<comments>https://blog.tomosia.com.vn/storybook-la-gi-cach-su-dung-storybook-trong-reactjs/#comments</comments>
		
		<dc:creator><![CDATA[admin_tomosia]]></dc:creator>
		<pubDate>Tue, 19 Dec 2023 06:21:45 +0000</pubDate>
				<category><![CDATA[ReactJS]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=2003</guid>

					<description><![CDATA[<p>1. Storybook là gì? Storybook là một công cụ phát triển giao diện người dùng (UI) cho các&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/storybook-la-gi-cach-su-dung-storybook-trong-reactjs/">Storybook là gì? Cách sử dụng storybook trong Reactjs</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 id="1-storybook-la-gi" class="wp-block-heading">1. Storybook là gì?</h2>



<p class="wp-block-paragraph">Storybook là một công cụ phát triển giao diện người dùng (UI) cho các ứng dụng web và ứng dụng di động. Nó cung cấp một môi trường phát triển tách biệt để xây dựng và kiểm thử các component giao diện của bạn mà không cần triển khai toàn bộ ứng dụng.</p>



<p class="wp-block-paragraph">Cụ thể, Storybook cho phép bạn xây dựng và hiển thị các &#8220;storybook&#8221; (&#8220;story&#8221;) cho từng component trong hệ thống của bạn. Mỗi &#8220;story&#8221; là một trạng thái hoặc biến thể của một component cụ thể, và bạn có thể tạo ra các &#8220;story&#8221; khác nhau để thử nghiệm và hiển thị các tính năng và trạng thái khác nhau của component đó.</p>



<p class="wp-block-paragraph">Công cụ này giúp nhóm phát triển tăng tốc quá trình phát triển và kiểm thử UI bằng cách tạo ra môi trường cô lập, thân thiện với người dùng để thử nghiệm và hiển thị các thành phần UI. Nó giúp đảm bảo rằng các component có thể tái sử dụng một cách đúng đắn và không bị ảnh hưởng bởi các yếu tố khác trong ứng dụng.</p>



<h2 id="2-install-storybook" class="wp-block-heading">2. Install storybook</h2>



<p class="wp-block-paragraph">Sử dụng npx:</p>



<pre class="wp-block-code"><code>npx storybook@latest init</code></pre>



<p class="wp-block-paragraph">yarn:</p>



<pre class="wp-block-code"><code>yarn dlx storybook@latest init</code></pre>



<p class="wp-block-paragraph">pnpm:</p>



<pre class="wp-block-code"><code>pnpm dlx storybook@latest init</code></pre>



<h2 id="3-start-storybook" class="wp-block-heading">3. Start storybook</h2>



<p class="wp-block-paragraph">Sau khi cài đặt thành công storybook mặc định câu lệnh chạy script trong pakage.json là:</p>



<pre class="wp-block-code"><code>"storybook": "storybook dev -p 6006"</code></pre>



<p class="wp-block-paragraph">Mặc định sẽ chạy port 6006. Để run script chạy lệnh:</p>



<pre class="wp-block-code"><code>yarn storybook
# or
npm run storybook</code></pre>



<p class="wp-block-paragraph">Sau khi chạy câu lệnh chúng ta sẽ có màn hình storybook trên <a href="http://localhost:6006/">localhost:6006</a></p>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="519" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-24-1024x519.png" alt="" class="wp-image-2011" style="width:680px;height:auto" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-24-1024x519.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-24-300x152.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-24-768x390.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-24-1536x779.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-24-380x193.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-24-800x406.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-24-1160x588.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-24.png 1853w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-video"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/example-browse-all-stories-optimized.mp4"></video></figure>



<p class="wp-block-paragraph">Trong thư mục code sẽ tự tạo 1 folder stories bao gồm 1 số component example:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="227" height="518" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-26.png" alt="" class="wp-image-2013" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-26.png 227w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-26-131x300.png 131w" sizes="auto, (max-width: 227px) 100vw, 227px" /></figure>



<p class="wp-block-paragraph">Ok các bạn có thể xóa thư mục này đi vì đây cũng chỉ là example, chúng ta sẽ tạo story cho các component của riêng dự án của chúng ta dưới đây.</p>



<h2 id="3-tao-storybook-cho-component" class="wp-block-heading">3. Tạo storybook cho component</h2>



<p class="wp-block-paragraph">Trước khi tạo storybook cho 1 component thì đương nhiên chúng ta sẽ phải có component chứ đúng không. Dưới đây mình sẽ tạo một BaseButton component:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.854167938232422px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="// BaseButton.jsx

import './base-button.css';

export const BaseButton = (props) =&gt; {
  const { children, primary, size, disable, ...buttonProps } = props;

  return (
    &lt;button
      className={[
        'button',
        `button--${size}`,
        primary ? 'button--primary' : 'button--secondary',
        disable ? 'button--disable' : '',
      ].join(' ')}
      {...buttonProps}
    &gt;
      {children}
    &lt;/button&gt;
  );
};" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B">// BaseButton.jsx</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">./base-button.css</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">BaseButton</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> (</span><span style="color: #FFB86C; font-style: italic">props</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> { children, primary, size, disable, </span><span style="color: #F286C4">...</span><span style="color: #F6F6F4">buttonProps } </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> props;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> (</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;</span><span style="color: #F286C4">button</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #62E884; font-style: italic">className</span><span style="color: #F286C4">={</span><span style="color: #F6F6F4">[</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">button</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #E7EE98">`button--</span><span style="color: #F286C4">${</span><span style="color: #F6F6F4">size</span><span style="color: #F286C4">}</span><span style="color: #E7EE98">`</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">        primary </span><span style="color: #F286C4">?</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">button--primary</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">button--secondary</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">        disable </span><span style="color: #F286C4">?</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">button--disable</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">      ].</span><span style="color: #62E884">join</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98"> </span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">)</span><span style="color: #F286C4">}</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">{...</span><span style="color: #F6F6F4">buttonProps</span><span style="color: #F286C4">}</span></span>
<span class="line"><span style="color: #F6F6F4">    &gt;</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">{</span><span style="color: #F6F6F4">children</span><span style="color: #F286C4">}</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;/</span><span style="color: #F286C4">button</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">  );</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.854167938232422px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">CSS</span><span role="button" tabindex="0" data-code="/* base-button.css */

.button {
  font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  font-weight: 500;
  border: 0;
  border-radius: 3em;
  cursor: pointer;
  display: inline-block;
  line-height: 1;
}
.button--primary {
  color: white;
  background-color: var(--primary-color);
}
.button--secondary {
  color: #333;
  background-color: transparent;
  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
}
.button--secondary:focus,
.button--secondary:focus-visible {
  color: var(--dark-primary-color);
  background-color: transparent;
  box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
}

.button--small {
  font-size: 12px;
  padding: 10px 16px;
}
.button--medium {
  font-size: 14px;
  padding: 11px 20px;
}
.button--large {
  font-size: 16px;
  padding: 12px 24px;
}

.button--disable {
  color: var(--disable-color);
  background-color: var(--disable-color);
  cursor: not-allowed;
}
.button--disable:focus,
.button--disable:focus-visible {
  outline: 4px auto var(--disable-color);
  background-color: var(--disable-color);
  color: var(--disable-color);
}
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B">/* base-button.css */</span></span>
<span class="line"></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">font-family</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">Nunito Sans</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">Helvetica Neue</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">Helvetica</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">Arial</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">sans-serif</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">font-weight</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">500</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">border</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">0</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">border-radius</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">3</span><span style="color: #F286C4">em</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">cursor</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">pointer</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">display</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">inline-block</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">line-height</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">1</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button--primary</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">color</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">white</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">background-color</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">var</span><span style="color: #F6F6F4">(--primary-color);</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button--secondary</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">color</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">#333</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">background-color</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">transparent</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">box-shadow</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">rgba</span><span style="color: #F6F6F4">(</span><span style="color: #BF9EEE">0</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">0</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">0</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">0.15</span><span style="color: #F6F6F4">) </span><span style="color: #BF9EEE">0</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">0</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">0</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">1</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">inset</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button--secondary</span><span style="color: #F286C4; font-style: italic">:</span><span style="color: #62E884; font-style: italic">focus</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button--secondary</span><span style="color: #F286C4; font-style: italic">:</span><span style="color: #62E884; font-style: italic">focus-visible</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">color</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">var</span><span style="color: #F6F6F4">(--dark-primary-color);</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">background-color</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">transparent</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">box-shadow</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">rgba</span><span style="color: #F6F6F4">(</span><span style="color: #BF9EEE">0</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">0</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">0</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">0.15</span><span style="color: #F6F6F4">) </span><span style="color: #BF9EEE">0</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">0</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">0</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">1</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">inset</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button--small</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">font-size</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">12</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">padding</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">10</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">16</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button--medium</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">font-size</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">14</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">padding</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">11</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">20</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button--large</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">font-size</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">16</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">padding</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">12</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">24</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button--disable</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">color</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">var</span><span style="color: #F6F6F4">(--disable-color);</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">background-color</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">var</span><span style="color: #F6F6F4">(--disable-color);</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">cursor</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">not-allowed</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button--disable</span><span style="color: #F286C4; font-style: italic">:</span><span style="color: #62E884; font-style: italic">focus</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #62E884; font-style: italic">.button--disable</span><span style="color: #F286C4; font-style: italic">:</span><span style="color: #62E884; font-style: italic">focus-visible</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">outline</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">4</span><span style="color: #F286C4">px</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">auto</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">var</span><span style="color: #F6F6F4">(--disable-color);</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">background-color</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">var</span><span style="color: #F6F6F4">(--disable-color);</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #97E1F1">color</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1">var</span><span style="color: #F6F6F4">(--disable-color);</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Sau khi tạo ra một BaseButton component chúng ta sẽ tạo một storybook cho nó. Mình cấu trúc file component như sau (các bạn có thể tùy chỉnh theo ý thích):</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="227" height="242" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-27.png" alt="" class="wp-image-2016"/></figure>



<p class="wp-block-paragraph">Mỗi component sẽ có một hoặc nhiều <strong>story</strong> cho thấy các trạng thái mà nó hỗ trợ. Bạn có thể hiển thị các stories trong giao diện người dùng và xem code đằng sau chúng trong các tệp kết thúc bằng <code>.stories.js</code>&nbsp;hoặc&nbsp;<code>.stories.ts</code></p>



<p class="wp-block-paragraph">Tạo 1 file BaseButton.stories.js hoặc BaseButton.stories.jsx:</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.854167938232422px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="// BaseButton.stories.js|jsx

import { BaseButton } from &quot;./BaseButton&quot;;

export default {
  component: BaseButton,
};

/*
 *👇 Render functions are a framework specific feature to allow you control on how the component renders.
 * See https://storybook.js.org/docs/react/api/csf
 * to learn how to use render functions.
 */
export const Primary = {
  render: () =&gt; &lt;BaseButton primary&gt;Button&lt;/BaseButton&gt;,
};" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B">// BaseButton.stories.js|jsx</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> { BaseButton } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">./BaseButton</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">default</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  component</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> BaseButton,</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B">/*</span></span>
<span class="line"><span style="color: #7B7F8B"> *👇 Render functions are a framework specific feature to allow you control on how the component renders.</span></span>
<span class="line"><span style="color: #7B7F8B"> * See https://storybook.js.org/docs/react/api/csf</span></span>
<span class="line"><span style="color: #7B7F8B"> * to learn how to use render functions.</span></span>
<span class="line"><span style="color: #7B7F8B"> */</span></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> Primary </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">render</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> () </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> &lt;</span><span style="color: #97E1F1; font-style: italic">BaseButton</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">primary</span><span style="color: #F6F6F4">&gt;Button&lt;/</span><span style="color: #97E1F1; font-style: italic">BaseButton</span><span style="color: #F6F6F4">&gt;,</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span></code></pre></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="507" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-29-1024x507.png" alt="" class="wp-image-2018" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-29-1024x507.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-29-300x148.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-29-768x380.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-29-1536x760.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-29-380x188.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-29-800x396.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-29-1160x574.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-29.png 1851w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Phía trên là ví dụ cách để render BaseButton ở trạng thái &#8220;primary&#8221; và xuất một story được gọi là <strong>Primary</strong>.</p>



<p class="wp-block-paragraph">Để mở rộng thêm lợi thế của <a href="https://storybook.js.org/docs/react/writing-stories/args">Storybook’s “args”</a>&nbsp;chúng ta sẽ khai báo thêm những Args mà BaseButton có như là: <em>primary, size, disable</em>&#8230;</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.854167938232422px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="import { BaseButton } from &quot;./BaseButton&quot;;

export default {
  title: 'BaseButton',
  component: BaseButton,
  parameters: {
    layout: 'centered',
  },
  tags: ['autodocs'],
  argTypes: {
    backgroundColor: { control: 'color' },
  },
};

export const Primary = {
  args: {
    primary: true,
    children: 'Click',
  },
};

export const Secondary = {
  args: {
    children: 'Click',
  },
};

export const Disable = {
  args: {
    children: 'Click',
    disable: true,
  },
};

export const Large = {
  args: {
    size: 'large',
    children: 'Click',
  },
};

export const Small = {
  args: {
    size: 'small',
    children: 'Click',
  },
};
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> { BaseButton } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">./BaseButton</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">default</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  title</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">BaseButton</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  component</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> BaseButton,</span></span>
<span class="line"><span style="color: #F6F6F4">  parameters</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    layout</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">centered</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">  tags</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> [</span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">autodocs</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">],</span></span>
<span class="line"><span style="color: #F6F6F4">  argTypes</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    backgroundColor</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> { control</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">color</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4"> },</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> Primary </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  args</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    primary</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">true</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">    children</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">Click</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> Secondary </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  args</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    children</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">Click</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> Disable </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  args</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    children</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">Click</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">    disable</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">true</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> Large </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  args</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    size</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">large</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">    children</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">Click</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> Small </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  args</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    size</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">small</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">    children</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">Click</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span>
<span class="line"></span></code></pre></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="507" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-31-1024x507.png" alt="" class="wp-image-2020" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-31-1024x507.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-31-300x148.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-31-768x380.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-31-1536x760.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-31-380x188.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-31-800x396.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-31-1160x574.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/image-31.png 1851w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Cả hai ví dụ về câu chuyện đều hiển thị cùng một nội dung vì Storybook cung cấp thuộc tính args đã cho vào story trong quá trình kết xuất. Nhưng bạn sẽ có được sự tiện lợi tiết kiệm thời gian với args.</p>



<h2 id="4-chinh-sua-mot-story" class="wp-block-heading">4. Chỉnh sửa một story</h2>



<p class="wp-block-paragraph">Storybook&nbsp;giúp bạn dễ dàng làm việc trên 1 component ở một trạng thái.&nbsp;Khi bạn edit code hoặc story của BaseButton. Storybook sẽ ngay lập tức hiển thị lại trong trình duyệt. Không cần phải reload lại trang.</p>



<figure class="wp-block-video"><video height="720" style="aspect-ratio: 1280 / 720;" width="1280" controls src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/example-button-hot-module-reload-optimized.mp4"></video></figure>



<h2 id="5-ket-luan" class="wp-block-heading">5. Kết luận</h2>



<p class="wp-block-paragraph"><br>Storybook là một công cụ phát triển và kiểm thử giao diện người dùng (UI) cho ứng dụng web và các dự án front-end khác. Dưới đây là một số công dụng chính của Storybook:</p>



<ol class="wp-block-list">
<li><strong>Phát triển và kiểm thử từng thành phần (Component):</strong> Storybook cho phép nhà phát triển tạo và xem các thành phần UI độc lập một cách riêng biệt từ ứng dụng chính. Điều này giúp chúng ta tập trung vào phát triển từng thành phần một cách hiệu quả hơn và kiểm thử chúng mà không cần khởi động toàn bộ ứng dụng.</li>



<li><strong>Tạo và quản lý hướng dẫn sử dụng (Documentation):</strong> Storybook giúp tạo ra một bản hướng dẫn sống cho các thành phần UI. Người phát triển có thể tạo các story (câu chuyện) để minh họa cách sử dụng và các trạng thái khác nhau của mỗi thành phần, làm cho việc tạo tài liệu trở nên dễ dàng.</li>



<li><strong>Kiểm thử tự động (Automated Testing):</strong> Storybook có thể được tích hợp với các công cụ kiểm thử tự động như Jest để đảm bảo rằng các thành phần UI hoạt động đúng như mong đợi và không gặp vấn đề sau khi thay đổi mã nguồn.</li>



<li><strong>Chia sẻ và tái sử dụng thành phần (Sharing and Reusability):</strong> Nhờ vào Storybook, các thành viên trong nhóm có thể dễ dàng chia sẻ và tái sử dụng các thành phần UI. Điều này giúp tạo ra một quy trình phát triển mở và linh hoạt hơn.</li>



<li><strong>Thử nghiệm các trạng thái và tương tác khác nhau:</strong> Storybook cho phép mô phỏng và kiểm thử các trạng thái khác nhau của các thành phần, cũng như tương tác của người dùng. Điều này giúp đảm bảo rằng UI của ứng dụng hoạt động chính xác trong mọi tình huống.</li>



<li><strong>Hỗ trợ nhanh chóng cho thiết kế (Design Support):</strong> Storybook là một công cụ hữu ích trong quá trình hợp tác giữa nhà phát triển và người thiết kế. Thiết kế có thể xem và tương tác với các thành phần UI mà không cần sự giúp đỡ từ ứng dụng chính.</li>
</ol>



<p class="wp-block-paragraph">Tóm lại, Storybook là một công cụ mạnh mẽ giúp tối ưu hóa quá trình phát triển và kiểm thử UI trong các dự án web và front-end.</p>



<p class="wp-block-paragraph">Tương tự như react chúng ta cũng có thể viết storybook cho vue và angular. Các bạn hãy đón xem bài viết tiếp theo về hướng dẫn viết storybook cho vue nhé.</p>



<p class="wp-block-paragraph">Tìm hiểu thêm ở trang chủ storybook nhé: <a href="https://storybook.js.org/">https://storybook.js.org/</a></p>
<p>The post <a href="https://blog.tomosia.com.vn/storybook-la-gi-cach-su-dung-storybook-trong-reactjs/">Storybook là gì? Cách sử dụng storybook trong Reactjs</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/storybook-la-gi-cach-su-dung-storybook-trong-reactjs/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		<enclosure url="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/example-browse-all-stories-optimized.mp4" length="65668" type="video/mp4" />
<enclosure url="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/example-button-hot-module-reload-optimized.mp4" length="97295" type="video/mp4" />

			</item>
		<item>
		<title>Async-IO, đa luồng và đơn luồng trong Javascript</title>
		<link>https://blog.tomosia.com.vn/async-io-da-luong-va-don-luong-trong-javascript/</link>
					<comments>https://blog.tomosia.com.vn/async-io-da-luong-va-don-luong-trong-javascript/#comments</comments>
		
		<dc:creator><![CDATA[Thâm Davies]]></dc:creator>
		<pubDate>Mon, 11 Dec 2023 01:36:12 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[single-threaded]]></category>
		<category><![CDATA[multi-threaded]]></category>
		<category><![CDATA[async-io]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=2396</guid>

					<description><![CDATA[<p>Nếu bạn muốn trở thành lập trình viên JS chuyên nghiệp hoặc đang học JS, việc hiểu rõ&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/async-io-da-luong-va-don-luong-trong-javascript/">Async-IO, đa luồng và đơn luồng trong Javascript</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Nếu bạn muốn trở thành lập trình viên JS chuyên nghiệp hoặc đang học JS, việc hiểu rõ về I/O bất đồng bộ và sự khác biệt so với đa luồng là điều cực kì quan trọng.</p>



<p class="wp-block-paragraph">Hãy cùng nhau xem xét cách một hoạt động đọc file blocking được thực hiện trong 3 trường hợp sau:</p>



<ul class="wp-block-list">
<li><strong>Đơn luồng (single-threaded):</strong>&nbsp;Chỉ xử lí được 1 công việc một lúc. Khi bắt đầu đọc file A, toàn bộ quy trình sẽ bị &#8220;đóng băng&#8221; cho đến khi hoàn tất. Lúc đó không thể đọc file B được.</li>



<li><strong>Đa luồng (multi-threaded):</strong>&nbsp;Khi luồng 1 bắt đầu đọc file A, chỉ riêng luồng 1 bị block, còn luồng 2 vẫn đọc được file B đồng thời.</li>



<li><strong>Đơn luồng với Async-IO (single-threaded with Async-IO):</strong>&nbsp;Khi gặp lệnh đọc file A, nó sẽ chuyển sang&nbsp;<a href="https://www.thamdavies.com/snippets/thread-pool-la-gi" target="_blank" rel="noreferrer noopener">thread pool</a>&nbsp;thực hiện. Luồng chính tiếp tục đọc file B. Khi xong sẽ trả kết quả về luồng chính bằng callback.</li>
</ul>



<p class="wp-block-paragraph">Nhờ đó trang web không bị &#8220;đóng băng&#8221; khi thực hiện nhiều yêu cầu đồng thời như gọi hàm&nbsp;<code>fetch()</code></p>


<div class="wp-block-image is-style-default">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="480" height="270" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/cheers.gif" alt="" class="wp-image-2400"/></figure>
</div>


<p class="wp-block-paragraph">Như vậy, chúng ta đã cùng nhau xét xem cách hoạt động đọc file blocking được thực hiện trong các mô hình đơn luồng, đa luồng và sử dụng thread pool. Việc nắm vững các khái niệm này giúp lập trình viên Javascript xử lý I/O hiệu quả, đảm bảo tính khả dụng và trải nghiệm người dùng. Enjoy coding 😘</p>



<p class="wp-block-paragraph">Bài viết gốc: <a href="https://www.thamdavies.com/blog/async-io-da-luong-va-don-luong-trong-javascript">https://www.thamdavies.com/blog/async-io-da-luong-va-don-luong-trong-javascript</a></p>
<p>The post <a href="https://blog.tomosia.com.vn/async-io-da-luong-va-don-luong-trong-javascript/">Async-IO, đa luồng và đơn luồng trong Javascript</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/async-io-da-luong-va-don-luong-trong-javascript/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Web 3 &#8211; Nền dân chủ kĩ thuật số. Kết nối ví với Web 3.0 bằng ReactJS</title>
		<link>https://blog.tomosia.com.vn/web-3-nen-dan-chu-ki-thuat-so-ket-noi-vi-voi-web-3-0-bang-reactjs/</link>
					<comments>https://blog.tomosia.com.vn/web-3-nen-dan-chu-ki-thuat-so-ket-noi-vi-voi-web-3-0-bang-reactjs/#comments</comments>
		
		<dc:creator><![CDATA[Anh Tien Tran]]></dc:creator>
		<pubDate>Fri, 08 Dec 2023 06:17:06 +0000</pubDate>
				<category><![CDATA[ReactJS]]></category>
		<category><![CDATA[Web3.0]]></category>
		<category><![CDATA[React]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=2276</guid>

					<description><![CDATA[<p>Ngược dòng lịch sử 1 chút, chúng ta cùng nhau tìm hiểu về 2 thời kì đã qua&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/web-3-nen-dan-chu-ki-thuat-so-ket-noi-vi-voi-web-3-0-bang-reactjs/">Web 3 &#8211; Nền dân chủ kĩ thuật số. Kết nối ví với Web 3.0 bằng ReactJS</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="585" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/web3-1024x585.png" alt="" class="wp-image-2278" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/web3-1024x585.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/web3-300x171.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/web3-768x439.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/web3-380x217.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/web3-800x457.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/web3-1160x663.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/web3.png 1400w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="has-text-align-left wp-block-paragraph">Ngược dòng lịch sử 1 chút, chúng ta cùng nhau tìm hiểu về 2 thời kì đã qua của Web 3.0.</p>



<h2 id="thu-vien-online-web-1-0" class="wp-block-heading">Thư viện online Web 1.0.</h2>



<p class="wp-block-paragraph">Web 1 được xem là thời kì khủng long của Internet với tiêu chí 3 KHÔNG: </p>



<ul class="wp-block-list">
<li>KHÔNG có sự tương tác, chỉ tiếp cận thông tin theo 1 chiều</li>



<li>KHÔNG bị quản lý bởi cá nhân hay tổ chức nào cả</li>



<li>KHÔNG có các thuật toán để sàng lọc thông tin. Khiến người dùng rất khó tìm thông tin liên quan</li>
</ul>



<p class="wp-block-paragraph">Sau tất cả, chúng ta có công thức chốt hạ cho Web 1.0</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>WEB1 = THE INTERNET OF INFORMATION; I.E., THE HTML CSS WEBSITES YOU CANNOT INTERACT WITH.</strong></p>



<p class="wp-block-paragraph"><sub><sup><em>Web1 = kỷ nguyên internet của không tin. Bao gồm HTML CSS và không thể tương tác.</em></sup></sub></p>
</blockquote>



<h2 id="web-2-0-xuat-hien-voi-dien-mao-moi-cai-tien-moi" class="wp-block-heading">Web 2.0 xuất hiện với diện mạo mới, cải tiến mới.</h2>



<p class="wp-block-paragraph">Năm 2005, Web 2.0 chính thức được ra đời với diện mạo mới. Được cải tiến từ Web 1.0 và một trong những thay đổi quan trọng lớn nhất đó là <strong>sự tương tác</strong>.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="2416" height="1422" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-7.58.32-PM.png" alt="" class="wp-image-2280" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-7.58.32-PM.png 2416w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-7.58.32-PM-300x177.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-7.58.32-PM-1024x603.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-7.58.32-PM-768x452.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-7.58.32-PM-1536x904.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-7.58.32-PM-2048x1205.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-7.58.32-PM-380x224.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-7.58.32-PM-800x471.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-7.58.32-PM-1160x683.png 1160w" sizes="auto, (max-width: 2416px) 100vw, 2416px" /></figure>



<p class="wp-block-paragraph">Khi bạn sử dụng Meta, Youtube,&#8230;những nền tảng này sẽ thu thập những thông tin của người dùng tìm kiếm để trả lại những thông tin phù hợp nhất.</p>



<p class="wp-block-paragraph">Cụ thể hơn tí nhé!  Khi bạn search trên Youtube với từ khoá là Blockchain, lúc này Youtube sẽ đề cử những video liên quan đến Blockchain. Từ ví dụ này chúng ta có thể thấy 1 điểm sáng tiếp theo của Web 2.0 đối với Web 1.0 đó chính là <strong>thuật toán</strong>. Web 2.0 sử dụng thuật toán để sàng lọc thông tin liên quan đến những cái mà người dùng quan tâm. </p>



<p class="wp-block-paragraph">Nghe đến đây, mọi người có đang nghĩ rằng Web 2 là đủ rồi, cần gì phải cải tiến hơn nữa?</p>



<p class="wp-block-paragraph">Không thể phũ nhận Web 2 có nhiều tiện ích và khả năng phát triển vô cùng lớn. Nhưng cái gì cũng có ưu và nhược điểm cả. Chắc hẳn mọi người cũng đã từng nghe qua cụm từ <strong>&#8220;Facebook nghe lén&#8221;</strong>. Đúng vậy, Web 2 đang dần lộ ra yếu điểm chính là việc thông tin cá nhân của người dùng bị xâm phạm. Những gã khổng lồ công nghệ như là Google, Meta, Amazon,&#8230; đang hằng ngày thu thập dữ liệu và bán cho các bên quảng cáo.</p>



<p class="wp-block-paragraph">Để giúp cho người dùng có thể kiểm soát được quyền riêng tư, cũng như là dữ liệu của mình. Thì đây là lúc Web 3 xuất hiện. Vậy Web 3.0 là gì nhỉ!</p>



<h2 id="web-3-0-nen-dan-chu-ki-thuat-so" class="wp-block-heading">Web 3.0 nền dân chủ kĩ thuật số.</h2>



<p class="wp-block-paragraph">Điểm sáng cho Web 3.0 là dựa vào công nghệ mở đường Blockchain, là loại hình công nghệ giúp lưu trữ, sắp xếp và quản lí thông tin trên mạng lưới Internet 1 cách phi tập trung</p>



<figure class="wp-block-image size-full is-style-default"><img loading="lazy" decoding="async" width="2294" height="1348" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-9.13.49-PM.png" alt="" class="wp-image-2298" style="aspect-ratio:16/9;object-fit:cover" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-9.13.49-PM.png 2294w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-9.13.49-PM-300x176.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-9.13.49-PM-1024x602.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-9.13.49-PM-768x451.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-9.13.49-PM-1536x903.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-9.13.49-PM-2048x1203.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-9.13.49-PM-380x223.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-9.13.49-PM-800x470.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screenshot-2023-12-04-at-9.13.49-PM-1160x682.png 1160w" sizes="auto, (max-width: 2294px) 100vw, 2294px" /></figure>



<p class="wp-block-paragraph">Các thiết bị chia sẻ thông tin 1 cách trực tiếp với nhau mà không cần phải chịu sự kiểm soát bởi cá nhân hay tổ chức nào. Có thể thấy bước cải tiến này của Web 3.0 đã ăn đứt Web 2.0 nhỉ. Nếu ở Web 2.0 quyền lợi của người dùng là rất mong manh và bị kiểm soát bởi các ông lớn công nghệ, thì Web 3.0 hứa hẹn người dùng chính là chủ sở hữu dữ liệu của họ, họ hoàn toàn có quyền quyết định và kiểm soát những dữ liệu đó.</p>



<p class="wp-block-paragraph">Với Web 3.0, những ca nhạc sĩ có thể trực tiếp đăng tải sản phẩm âm nhạc của họ lên mạng thông qua công nghệ Blockchain. Sản phẩm sẽ được số hoá thành Token hoặc NFT. Họ có thể kiếm lợi nhuận từ việc bán sản phẩm đó và hoàn toàn loại bỏ được bên thứ 3.</p>



<p class="wp-block-paragraph">Web 3.0 ra đời là mối đe doạ đến các ông lớn. Nó thay <strong>đổi luật chơi</strong>, <strong>loại bỏ trung gian</strong> và <strong>sang bằng lợi nhuận</strong>.</p>



<h2 id="connect-wallet-with-web3-react" class="wp-block-heading">Connect wallet with Web3-React</h2>



<p class="wp-block-paragraph">Step 1: Cài đặt ethers và web3-react</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="npm i ethers@5.5.4
npm i @web3-react/core@6.1.9" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F6F6F4">npm i ethers@</span><span style="color: #BF9EEE">5.5</span><span style="color: #F6F6F4">.</span><span style="color: #BF9EEE">4</span></span>
<span class="line"><span style="color: #F6F6F4">npm i @</span><span style="color: #62E884; font-style: italic">web3</span><span style="color: #F286C4">-</span><span style="color: #62E884; font-style: italic">react</span><span style="color: #F286C4">/</span><span style="color: #62E884; font-style: italic">core</span><span style="color: #F6F6F4">@</span><span style="color: #BF9EEE">6.1</span><span style="color: #F6F6F4">.</span><span style="color: #BF9EEE">9</span></span></code></pre></div>



<p class="wp-block-paragraph">Step 2: Khởi tạo Web3ReactProvider</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">TypeScript</span><span role="button" tabindex="0" data-code="import { Web3ReactProvider } from &quot;@web3-react/core&quot;;
import { ethers } from &quot;ethers&quot;;

const getLibrary = (provider: any) =&gt; {
  return new ethers.providers.Web3Provider(provider);
}

&lt;React.StrictMode&gt;
  &lt;Web3ReactProvider getLibrary={getLibrary}&gt;
    &lt;App /&gt;
  &lt;/Web3ReactProvider&gt;
&lt;/React.StrictMode&gt;
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> { Web3ReactProvider } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">@web3-react/core</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> { ethers } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">ethers</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">getLibrary</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> (</span><span style="color: #FFB86C; font-style: italic">provider</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">any</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> ethers.providers.</span><span style="color: #62E884">Web3Provider</span><span style="color: #F6F6F4">(provider);</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4">React.StrictMode</span><span style="color: #F286C4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4">Web3ReactProvider getLibrary</span><span style="color: #F286C4">=</span><span style="color: #F6F6F4">{getLibrary}</span><span style="color: #F286C4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4">App </span><span style="color: #F286C4">/&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">&lt;/</span><span style="color: #F6F6F4">Web3ReactProvider</span><span style="color: #F286C4">&gt;</span></span>
<span class="line"><span style="color: #F286C4">&lt;/</span><span style="color: #F6F6F4">React.StrictMode</span><span style="color: #F286C4">&gt;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Step 3: Cài đặt Wallet Connectors</p>



<div class="wp-block-kevinbatdorf-code-block-pro alignwide cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="npm i @web3-react/walletlink-connector # Coinbase Wallet
npm i @web3-react/injected-connector # Metamask" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F6F6F4">npm i @</span><span style="color: #62E884; font-style: italic">web3</span><span style="color: #F286C4">-</span><span style="color: #62E884; font-style: italic">react</span><span style="color: #F286C4">/</span><span style="color: #62E884; font-style: italic">walletlink</span><span style="color: #F286C4">-</span><span style="color: #62E884; font-style: italic">connector</span><span style="color: #F6F6F4"> # Coinbase Wallet</span></span>
<span class="line"><span style="color: #F6F6F4">npm i @</span><span style="color: #62E884; font-style: italic">web3</span><span style="color: #F286C4">-</span><span style="color: #62E884; font-style: italic">react</span><span style="color: #F286C4">/</span><span style="color: #62E884; font-style: italic">injected</span><span style="color: #F286C4">-</span><span style="color: #62E884; font-style: italic">connector</span><span style="color: #F6F6F4"> # Metamask</span></span></code></pre></div>



<p class="wp-block-paragraph">Tạo file <strong>connectors.ts</strong> với mục đích khởi tạo các trình kết nối để tích hợp vào app của mình</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">TypeScript</span><span role="button" tabindex="0" data-code="import { InjectedConnector } from &quot;@web3-react/injected-connector&quot;;
import { WalletLinkConnector } from &quot;@web3-react/walletlink-connector&quot;;

const injected = new InjectedConnector({
  supportedChainIds: [1, 5],
});

const coinbaseWallet = new WalletLinkConnector({
  url: `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`,
  appName: &quot;web3-react-demo&quot;,
});

export const connectors = {
  injected: injected,
  coinbaseWallet: coinbaseWallet,
};" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> { InjectedConnector } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">@web3-react/injected-connector</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> { WalletLinkConnector } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">@web3-react/walletlink-connector</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> injected </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">InjectedConnector</span><span style="color: #F6F6F4">({</span></span>
<span class="line"><span style="color: #F6F6F4">  supportedChainIds</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> [</span><span style="color: #BF9EEE">1</span><span style="color: #F6F6F4">, </span><span style="color: #BF9EEE">5</span><span style="color: #F6F6F4">],</span></span>
<span class="line"><span style="color: #F6F6F4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> coinbaseWallet </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">WalletLinkConnector</span><span style="color: #F6F6F4">({</span></span>
<span class="line"><span style="color: #F6F6F4">  url</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">`https://mainnet.infura.io/v3/</span><span style="color: #F286C4">${</span><span style="color: #F6F6F4">process.env.</span><span style="color: #BF9EEE">INFURA_KEY</span><span style="color: #F286C4">}</span><span style="color: #E7EE98">`</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  appName</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">web3-react-demo</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> connectors </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  injected</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> injected,</span></span>
<span class="line"><span style="color: #F6F6F4">  coinbaseWallet</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> coinbaseWallet,</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span></code></pre></div>



<ul class="wp-block-list">
<li><strong>supportedChainIds</strong>: Nó được sử dụng để xác định danh sách các chainId (ID chuỗi) mà một ứng dụng hoặc một thư viện hỗ trợ. Mỗi mạng Ethereum hoặc chuỗi con có một chainId duy nhất để xác định nó. Tham khảo https://chainlist.org/</li>



<li><strong>INFURA_KEY</strong>: là một khóa API được sử dụng để kết nối ứng dụng của bạn với mạng Ethereum và IPFS thông qua dịch vụ Infura. Tham khảo https://www.infura.io/</li>
</ul>



<p class="wp-block-paragraph">Step 4: Connect and Disconnect from Wallet</p>



<p class="wp-block-paragraph">Trong file <strong>App.tsx</strong> sử dụng <strong>useWeb3React</strong> hook để connect và disconnect ví</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="&lt;import { useWeb3React } from '@web3-react/core'" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F6F6F4">&lt;</span><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">{</span><span style="color: #F6F6F4"> useWeb3React </span><span style="color: #F286C4">}</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">@web3-react/core</span><span style="color: #DEE492">&#39;</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="function App() {
  
  const { activate, deactivate } = useWeb3React();
    ...
}" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">function</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">App</span><span style="color: #F6F6F4">() {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> { activate, deactivate } </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">useWeb3React</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">...</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span></code></pre></div>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">TypeScript</span><span role="button" tabindex="0" data-code="&lt;button onClick={() =&gt; { activate(connectors.coinbaseWallet) }}&gt;
  Coinbase Wallet
&lt;/button&gt;

&lt;button onClick={() =&gt; {
  if (window.ethereum) {
    activate(connectors.injected);
  } else {
    alert(&quot;Please install Meta Mask Extension&quot;);
  }
}}&gt;
  Meta Mask
&lt;/button&gt;

&lt;button onClick={deactivate}&gt;Disconnect&lt;/button&gt;" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4">button onClick</span><span style="color: #F286C4">=</span><span style="color: #F6F6F4">{() =&gt; { </span><span style="color: #62E884">activate</span><span style="color: #F6F6F4">(connectors.coinbaseWallet) }}</span><span style="color: #F286C4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">  Coinbase Wallet</span></span>
<span class="line"><span style="color: #F286C4">&lt;/</span><span style="color: #F6F6F4">button</span><span style="color: #F286C4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4">button onClick</span><span style="color: #F286C4">=</span><span style="color: #F6F6F4">{() =&gt; {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (window.ethereum) {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #62E884">activate</span><span style="color: #F6F6F4">(connectors.injected);</span></span>
<span class="line"><span style="color: #F6F6F4">  } </span><span style="color: #F286C4">else</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #62E884">alert</span><span style="color: #F6F6F4">(</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">Please install Meta Mask Extension</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">);</span></span>
<span class="line"><span style="color: #F6F6F4">  }</span></span>
<span class="line"><span style="color: #F6F6F4">}}</span><span style="color: #F286C4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">  Meta Mask</span></span>
<span class="line"><span style="color: #F286C4">&lt;/</span><span style="color: #F6F6F4">button</span><span style="color: #F286C4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">&lt;</span><span style="color: #F6F6F4">button onClick</span><span style="color: #F286C4">=</span><span style="color: #F6F6F4">{deactivate}</span><span style="color: #F286C4">&gt;</span><span style="color: #F6F6F4">Disconnect</span><span style="color: #F286C4">&lt;/</span><span style="color: #F6F6F4">button</span><span style="color: #F286C4">&gt;</span></span></code></pre></div>



<p class="wp-block-paragraph">Cùng xem demo nhé. </p>



<figure class="wp-block-video"><video height="1800" style="aspect-ratio: 2880 / 1800;" width="2880" controls src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screen-Recording-2023-12-06-at-1.22.21-PM.mov"></video></figure>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Cảm ơn mọi người đã đọc ^^</p>



<p class="wp-block-paragraph"></p>



<p class="wp-block-paragraph">Nguồn tham khảo:</p>



<p class="wp-block-paragraph"><em><a href="https://docs.cloud.coinbase.com/wallet-sdk/docs/web3-react">https://docs.cloud.coinbase.com/wallet-sdk/docs/web3-react</a></em></p>



<p class="wp-block-paragraph"><em><a href="https://www.youtube.com/watch?v=6xZdv1hiphg&amp;t=362s">https://www.youtube.com/watch?v=6xZdv1hiphg&amp;t=362s</a></em></p>
<p>The post <a href="https://blog.tomosia.com.vn/web-3-nen-dan-chu-ki-thuat-so-ket-noi-vi-voi-web-3-0-bang-reactjs/">Web 3 &#8211; Nền dân chủ kĩ thuật số. Kết nối ví với Web 3.0 bằng ReactJS</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/web-3-nen-dan-chu-ki-thuat-so-ket-noi-vi-voi-web-3-0-bang-reactjs/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		<enclosure url="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/Screen-Recording-2023-12-06-at-1.22.21-PM.mov" length="11502414" type="video/quicktime" />

			</item>
		<item>
		<title>Vuex vs Pinia: So sánh các thư viện quản lý State Vue</title>
		<link>https://blog.tomosia.com.vn/vuex-vs-pinia-so-sanh-cac-thu-vien-quan-ly-state-vue/</link>
					<comments>https://blog.tomosia.com.vn/vuex-vs-pinia-so-sanh-cac-thu-vien-quan-ly-state-vue/#comments</comments>
		
		<dc:creator><![CDATA[Tien Ho]]></dc:creator>
		<pubDate>Tue, 05 Dec 2023 02:17:23 +0000</pubDate>
				<category><![CDATA[VueJS]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=2243</guid>

					<description><![CDATA[<p>Vuex và Pinia là hai thư viện quản lý trạng thái cho các ứng dụng Vue.js.&#160;Vuex là thư&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/vuex-vs-pinia-so-sanh-cac-thu-vien-quan-ly-state-vue/">Vuex vs Pinia: So sánh các thư viện quản lý State Vue</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="576" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/state-1024x576.png" alt="" class="wp-image-2244" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/state-1024x576.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/state-300x169.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/state-768x432.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/state-380x214.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/state-800x450.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/state-1160x653.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/state.png 1280w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Vuex và Pinia là hai thư viện quản lý trạng thái cho các ứng dụng Vue.js.&nbsp;Vuex là thư viện cũ hơn và lâu đời hơn, nhưng Pinia đang trở nên phổ biến nhờ API đơn giản hơn và hỗ trợ TypeScript tốt hơn.</p>



<h2 id="quan-ly-state-la-gi" class="wp-block-heading">Quản lý state là gì?</h2>



<p class="wp-block-paragraph">Quản lý state là quá trình quản lý dữ liệu được chia sẻ giữa các thành phần khác nhau trong ứng dụng Vue.&nbsp;Điều này có thể phức tạp, đặc biệt đối với các ứng dụng phức tạp, nơi cần có các thư viện quản lý trạng thái như Vuex và Pinia.</p>



<h2 class="wp-block-heading has-large-font-size" id="ember40"><span id="vuex">Vuex</span></h2>



<p class="wp-block-paragraph" id="ember41">Vuex là một thư viện quản lý trạng thái (state management) cho ứng dụng Vue.js. Nó giữ trạng thái của ứng dụng trong một trung tâm duy nhất gọi là &#8220;store&#8221;. Vuex cũng cung cấp một số tính năng giúp quản lý trạng thái dễ dàng, chẳng hạn như:</p>



<ul class="wp-block-list">
<li><strong>Mutations:</strong> là các hàm thuần túy cập nhật trạng thái theo cách có thể dự đoán được.</li>



<li><strong>Actions:</strong> là các hàm không đồng bộ có thể được sử dụng để thực hiện các tác vụ cập nhật trạng thái, chẳng hạn như tìm nạp dữ liệu từ API.</li>



<li><strong>Getters:</strong> là các hàm thuần túy có thể được sử dụng để tính toán các giá trị từ trạng thái.</li>
</ul>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="880" height="585" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/image_state.png" alt="" class="wp-image-2246" style="width:680px;height:auto" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image_state.png 880w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image_state-300x199.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image_state-768x511.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image_state-380x253.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image_state-800x532.png 800w" sizes="auto, (max-width: 880px) 100vw, 880px" /></figure>



<h2 id="pinia" class="wp-block-heading">Pinia</h2>



<p class="wp-block-paragraph" id="ember46">Pinia cũng là một thư viện quản lý trạng thái, nhưng được thiết kế với mô hình dựa trên cơ sở TypeScript. Nó khuyến khích sử dụng các cửa hàng cụ thể cho từng phần của ứng dụng. Điều này có nghĩa là mỗi thành phần có thể có cửa hàng riêng, chứa trạng thái dành riêng cho thành phần đó.&nbsp;Pinia cũng cung cấp một số tính năng giúp quản lý trạng thái dễ dàng, chẳng hạn như:</p>



<ul class="wp-block-list">
<li><strong>Hỗ trợ Composition API:</strong> &nbsp;API của Pinia được thiết kế để sử dụng với Vue Composition API, giúp dễ dàng tạo và quản lý trạng thái theo cách mô-đun.</li>



<li><strong>Hỗ trợ TypeScript:</strong> &nbsp;Pinia có hỗ trợ TypeScript tích hợp, giúp bạn dễ dàng viết mã an toàn.</li>



<li><strong>Hỗ trợ Devtools:</strong> &nbsp;Pinia hỗ trợ Vue Devtools, giúp bạn dễ dàng gỡ lỗi và kiểm tra trạng thái của mình.</li>
</ul>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1024" height="370" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/pinia.png" alt="" class="wp-image-2251" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/pinia.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/pinia-300x108.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/pinia-768x278.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/pinia-380x137.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/pinia-800x289.png 800w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 id="ban-nen-su-dung-pinia-hay-vuex" class="wp-block-heading">Bạn nên sử dụng Pinia hay Vuex?</h2>



<p class="wp-block-paragraph">Mặc dù Pinia đã được công nhận là giải pháp quản lý trạng thái chính thức cho các ứng dụng Vue trong tương lai nhưng điều đó không có nghĩa là Vuex không còn được dùng nữa.&nbsp;Nếu bạn có một ứng dụng đang được sản xuất và sử dụng Vuex thì ứng dụng của bạn sẽ vẫn hoạt động tốt và bạn nên tiếp tục sử dụng Vuex vì việc di chuyển từ thư viện này sang thư viện khác có thể tốn rất nhiều công sức.</p>



<p class="wp-block-paragraph">Tuy nhiên, nếu dự án của bạn vẫn đang trong giai đoạn phát triển ban đầu thì Pinia là lựa chọn phù hợp.&nbsp;Bạn sẽ được hưởng lợi từ cú pháp dễ hiểu và đơn giản hơn của Pinia cùng với các tính năng khác được đề cập trong bài viết này.</p>



<p class="wp-block-paragraph"><strong>Dưới đây là bảng tóm tắt những điểm khác biệt chính giữa Vuex và Pinia:</strong></p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="437" height="396" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/vuex-pinia.png" alt="" class="wp-image-2258" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/vuex-pinia.png 437w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/vuex-pinia-300x272.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/vuex-pinia-380x344.png 380w" sizes="auto, (max-width: 437px) 100vw, 437px" /></figure>



<h2 id="tai-sao-chon-pinia-thay-the-vuex" class="wp-block-heading" style="text-transform:capitalize">Tại sao chọn Pinia thay thế Vuex?</h2>



<p class="wp-block-paragraph">Trong số các ưu điểm của thư viện Pinia, cá nhân mình thấy nó nổi trội nhất ở các điểm sau:</p>



<ul class="wp-block-list">
<li>Kích thước thư viện siêu nhẹ, chỉ khoảng 1kb</li>



<li>Hỗ trợ module hóa tốt</li>



<li>Hỗ trợ auto complete khi code tốt. Thay vì phải khai báo mapAction(…), mapGetter(…).v.v…</li>



<li>Dễ sử dụng, vì cách viết giống như bạn vẫn khai báo và sử dụng state trong từng component vậy.</li>
</ul>



<p class="wp-block-paragraph">Và còn nhiều ưu điểm khác nữa. Mình nghĩ sau khi thực hành và ứng dụng vào dự án, bạn sẽ trải nghiệm và nhận ra các ưu điểm này.</p>



<p class="wp-block-paragraph">Cảm ơn mọi người đã dành thời gian để đọc 🙏  </p>



<p class="wp-block-paragraph">Have a nice day!</p>
<p>The post <a href="https://blog.tomosia.com.vn/vuex-vs-pinia-so-sanh-cac-thu-vien-quan-ly-state-vue/">Vuex vs Pinia: So sánh các thư viện quản lý State Vue</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/vuex-vs-pinia-so-sanh-cac-thu-vien-quan-ly-state-vue/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title>Refresh token trong Axios như thế nào?</title>
		<link>https://blog.tomosia.com.vn/refresh-token-trong-axios-nhu-the-nao/</link>
					<comments>https://blog.tomosia.com.vn/refresh-token-trong-axios-nhu-the-nao/#comments</comments>
		
		<dc:creator><![CDATA[Tien Ho]]></dc:creator>
		<pubDate>Mon, 04 Dec 2023 01:38:25 +0000</pubDate>
				<category><![CDATA[VueJS]]></category>
		<category><![CDATA[ReactJS]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=2211</guid>

					<description><![CDATA[<p>Sau đây, mình sẽ chia sẻ 1 tính năng đó là refresh token mà mình đã thực hiện&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/refresh-token-trong-axios-nhu-the-nao/">Refresh token trong Axios như thế nào?</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Sau đây, mình sẽ chia sẻ 1 tính năng đó là refresh token mà mình đã thực hiện trong dự án của mình. Mình nghĩ sẽ có nhiều dự án sẽ cần đến, sẽ giúp đến bạn :)))) </p>



<p class="wp-block-paragraph">Về việc triển khai&nbsp;<code>refresh token</code>&nbsp;có thể không còn xa lạ đối với nhiều Frontend Dev trong chúng ta. Sau khi đăng nhập thành công,&nbsp;<code>token</code> sẽ được trả lại từ API (Thông thường api sẽ trả về <code>access_token</code> và <code>refresh_token</code>). </p>



<p class="wp-block-paragraph">Chúng ta sẽ lưu trữ nó lại ở localStorage, cookie, etc&#8230; để đính vào headers của mỗi request cho việc xác thực các request mà chúng ta gửi đi.</p>



<p class="wp-block-paragraph">Khi&nbsp;<code>token</code>&nbsp;này hết hạn, chúng ta sẽ cần gửi một yêu cầu để lấy một&nbsp;<code>token</code>&nbsp;mới bằng việc gửi&nbsp;<code>token</code>&nbsp;hết hạn trước đó hoặc mã&nbsp;<code>refresh_token</code>&nbsp;ban đầu được trả về từ API. Việc này phụ thuộc vào thiết kế API đó.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="369" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/12/image-4-1024x369.png" alt="" class="wp-image-2212" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image-4-1024x369.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image-4-300x108.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image-4-768x277.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image-4-1536x554.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image-4-2048x738.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image-4-380x137.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image-4-800x288.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image-4-1160x418.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/12/image-4.png 2058w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Trước khi biết khi nào token hết hạn, chúng ta cần đính&nbsp;<code>token</code>&nbsp;vào mỗi request gửi đi. Bạn có thể hình dung việc chúng ta đính token vào mỗi request như thế này, để đảm bảo chúng ta luôn gửi&nbsp;<code>token</code>&nbsp;đến API để xác thực và biết khi nào token sẽ hết hạn (Tránh tự ý kiểm tra token ở client, việc đó không thực sự an toàn).</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="const axiosClient = axios.create({
  baseURL: process.env.PR_API_HOST,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Add a request interceptor
axiosClient.interceptors.request.use(
  (config) =&gt; {
    const storage = useStorage();
    const accessToken = storage.getItem(StorageKeyEnum.AccessToken);
  
    if (accessToken &amp;&amp; config.headers) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }
    return config;
  },
  (error) =&gt; Promise.reject(error)
);" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> axiosClient </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> axios.</span><span style="color: #62E884">create</span><span style="color: #F6F6F4">({</span></span>
<span class="line"><span style="color: #F6F6F4">  baseURL</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> process.env.</span><span style="color: #BF9EEE">PR_API_HOST</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  headers</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">Content-Type</span><span style="color: #DEE492">&#39;</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">application/json</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B">// Add a request interceptor</span></span>
<span class="line"><span style="color: #F6F6F4">axiosClient.interceptors.request.</span><span style="color: #62E884">use</span><span style="color: #F6F6F4">(</span></span>
<span class="line"><span style="color: #F6F6F4">  (</span><span style="color: #FFB86C; font-style: italic">config</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> storage </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">useStorage</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> accessToken </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> storage.</span><span style="color: #62E884">getItem</span><span style="color: #F6F6F4">(StorageKeyEnum.AccessToken);</span></span>
<span class="line"><span style="color: #F6F6F4">  </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (accessToken </span><span style="color: #F286C4">&amp;&amp;</span><span style="color: #F6F6F4"> config.headers) {</span></span>
<span class="line"><span style="color: #F6F6F4">      config.headers.Authorization </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">`Bearer </span><span style="color: #F286C4">${</span><span style="color: #F6F6F4">accessToken</span><span style="color: #F286C4">}</span><span style="color: #E7EE98">`</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> config;</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">  (</span><span style="color: #FFB86C; font-style: italic">error</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Promise</span><span style="color: #F6F6F4">.</span><span style="color: #62E884">reject</span><span style="color: #F6F6F4">(error)</span></span>
<span class="line"><span style="color: #F6F6F4">);</span></span></code></pre></div>



<p class="wp-block-paragraph">Khi mỗi request cần xác thực được gửi đi với&nbsp;<code>token</code>&nbsp;kèm theo, chúng ta sẽ biết&nbsp;<code>token</code>&nbsp;đó còn hợp lệ hay không bằng việc API sẽ giúp chúng ta xác minh token đó. khi&nbsp;<code>token</code>&nbsp;hết hạn, thông thường chúng ta sẽ nhận được mã phản hồi là&nbsp;<strong>401</strong>&nbsp;hoặc&nbsp;<strong>403</strong>.</p>



<p class="wp-block-paragraph">Khi đó, chúng ta sẽ kiểm tra trên mỗi response nhận về. Nếu nó rơi vào các mã lỗi trên, thực hiện kịch bản&nbsp;<code>refresh token</code>&nbsp;mà chúng ta muốn. Ở bên dưới đoạn code này, hiện tại dự án của mình khi hết hạn token trả về mã lỗi là <strong>401</strong> và kèm theo 1 message <code>Signature has expired </code>nên mình đang thực hiện check theo điều kiện như vậy nhé =))) </p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="axiosClient.interceptors.response.use(
  (response) =&gt; response.data,
  async (error) =&gt; {
    let message = '';
    const originalConfig = error.config;
    const code = error.response &amp;&amp; Number(error.response.status);
    switch (code) {
      case 401:
        if (error.response.data.error === RESPONSE_ERROR_MESSAGE.SIGNATURE_HAS_EXPIRED) {
          // Chúng ta sẽ refresh token tại đây
        break;
      case ...:
        break;
      default:
        message = ErrorHttpMessageEnum.Default;
      
    }
    return message;
  },
);" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F6F6F4">axiosClient.interceptors.response.</span><span style="color: #62E884">use</span><span style="color: #F6F6F4">(</span></span>
<span class="line"><span style="color: #F6F6F4">  (</span><span style="color: #FFB86C; font-style: italic">response</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> response.data,</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">async</span><span style="color: #F6F6F4"> (</span><span style="color: #FFB86C; font-style: italic">error</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">let</span><span style="color: #F6F6F4"> message </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;&#39;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> originalConfig </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> error.config;</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> code </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> error.response </span><span style="color: #F286C4">&amp;&amp;</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">Number</span><span style="color: #F6F6F4">(error.response.status);</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">switch</span><span style="color: #F6F6F4"> (code) {</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">case</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">401</span><span style="color: #F6F6F4">:</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (error.response.data.error </span><span style="color: #F286C4">===</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">RESPONSE_ERROR_MESSAGE</span><span style="color: #F6F6F4">.</span><span style="color: #BF9EEE">SIGNATURE_HAS_EXPIRED</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">          </span><span style="color: #7B7F8B">// Chúng ta sẽ refresh token tại đây</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">break</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">case</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">...</span><span style="color: #F6F6F4">:</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">break</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">default</span><span style="color: #F6F6F4">:</span></span>
<span class="line"><span style="color: #F6F6F4">        message </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> ErrorHttpMessageEnum.Default;</span></span>
<span class="line"><span style="color: #F6F6F4">      </span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> message;</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">);</span></span></code></pre></div>



<p class="wp-block-paragraph">Tiếp theo, để đảm bảo chỉ một request refresh token được tạo ra khi nhiều request với token hết hạn phát sinh khi tải trang, chúng ta sẽ cần sử dụng Promise để delay và chỉ tạo duy nhất một yêu cầu cuối cùng. Kèm theo đó, là kiểm tra xem có request refresh token nào đã được gọi thông qua biến trạng thái<code> isRefreshing</code></p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="// refresh token is false, to call refresh token api
if (!isRefreshing) {
// update status isRefreshing to be true
  isRefreshing = true;
  // this method fetches the new token
  refreshTokensLoginApi().then(() =&gt; {
    const storage = useStorage();
    const accessToken = storage.getItem(StorageKeyEnum.AccessToken);
    onRefreshed(accessToken);
    // after that, to clear all setup
    refreshSubscribers = [];
    isRefreshing = false;
  });
}

// setup callback to change token in headers authorization
const retryOrigReq = new Promise((resolve) =&gt; {
  subscribeTokenRefresh((token: string) =&gt; {
    // replace the expired token and retry
    originalConfig.headers.Authorization = `Bearer ${token}`;
    resolve(axiosClient(originalConfig));
  });
});

return retryOrigReq;

const subscribeTokenRefresh = (cb: (token: string) =&gt; void) =&gt; {
  refreshSubscribers.push(cb);
};

const onRefreshed = (token: string) =&gt; {
  refreshSubscribers.map((cb) =&gt; cb(token));
};" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #7B7F8B">// refresh token is false, to call refresh token api</span></span>
<span class="line"><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (</span><span style="color: #F286C4">!</span><span style="color: #F6F6F4">isRefreshing) {</span></span>
<span class="line"><span style="color: #7B7F8B">// update status isRefreshing to be true</span></span>
<span class="line"><span style="color: #F6F6F4">  isRefreshing </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">true</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #7B7F8B">// this method fetches the new token</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">refreshTokensLoginApi</span><span style="color: #F6F6F4">().</span><span style="color: #62E884">then</span><span style="color: #F6F6F4">(() </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> storage </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">useStorage</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> accessToken </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> storage.</span><span style="color: #62E884">getItem</span><span style="color: #F6F6F4">(StorageKeyEnum.AccessToken);</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #62E884">onRefreshed</span><span style="color: #F6F6F4">(accessToken);</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #7B7F8B">// after that, to clear all setup</span></span>
<span class="line"><span style="color: #F6F6F4">    refreshSubscribers </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> [];</span></span>
<span class="line"><span style="color: #F6F6F4">    isRefreshing </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">  });</span></span>
<span class="line"><span style="color: #F6F6F4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B">// setup callback to change token in headers authorization</span></span>
<span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> retryOrigReq </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Promise</span><span style="color: #F6F6F4">((</span><span style="color: #FFB86C; font-style: italic">resolve</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #62E884">subscribeTokenRefresh</span><span style="color: #F6F6F4">((</span><span style="color: #FFB86C; font-style: italic">token</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">string</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #7B7F8B">// replace the expired token and retry</span></span>
<span class="line"><span style="color: #F6F6F4">    originalConfig.headers.Authorization </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">`Bearer </span><span style="color: #F286C4">${</span><span style="color: #F6F6F4">token</span><span style="color: #F286C4">}</span><span style="color: #E7EE98">`</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #62E884">resolve</span><span style="color: #F6F6F4">(</span><span style="color: #62E884">axiosClient</span><span style="color: #F6F6F4">(originalConfig));</span></span>
<span class="line"><span style="color: #F6F6F4">  });</span></span>
<span class="line"><span style="color: #F6F6F4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> retryOrigReq;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">subscribeTokenRefresh</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> (</span><span style="color: #62E884">cb</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> (</span><span style="color: #FFB86C; font-style: italic">token</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">string</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  refreshSubscribers.</span><span style="color: #62E884">push</span><span style="color: #F6F6F4">(cb);</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">onRefreshed</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> (</span><span style="color: #FFB86C; font-style: italic">token</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">string</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  refreshSubscribers.</span><span style="color: #62E884">map</span><span style="color: #F6F6F4">((</span><span style="color: #FFB86C; font-style: italic">cb</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">cb</span><span style="color: #F6F6F4">(token));</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span></code></pre></div>



<p class="wp-block-paragraph">Ở đây,&nbsp;<code>useStorage()</code>&nbsp;là mình đang viết 1 hook để tương tác <code>get, set, remove token</code> với các storage.&nbsp;Mục đích mình viết hooks để mình tái sử dụng lại cho được nhiều components trong dự án đó, thay vì mình phải viết lại từng nơi. Nó giúp code trong dự án mình tường minh, dễ quản lý hơn, tránh lặp lại code.</p>



<p class="wp-block-paragraph">Tóm gọn lại, chúng ta sẽ có một hàm&nbsp;<code>refresh token&nbsp;</code>như bên dưới.</p>



<div class="wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="import axios from 'axios';
import {
  ErrorHttpMessageEnum, StorageKeyEnum, RESPONSE_ERROR_MESSAGE
} from 'src/constant';
import { refreshTokensLoginApi, clearTokenRedirectLogin } from 'src/helpers/auth';
import { useStorage } from 'src/hooks/useStorage';

let isRefreshing = false;
let refreshSubscribers: ((token: string) =&gt; void)[] = [];

const axiosClient = axios.create({
  baseURL: process.env.PR_API_HOST,
  headers: {
    'Content-Type': 'application/json',
  },
});

// Add a request interceptor
axiosClient.interceptors.request.use(
  (config) =&gt; {
    const storage = useStorage();
    const accessToken = storage.getItem(StorageKeyEnum.AccessToken);
    
    if (accessToken &amp;&amp; config.headers) {
      config.headers.Authorization = `Bearer ${accessToken}`;
    }
    return config;
  },
  (error) =&gt; Promise.reject(error)
);

// Add a response interceptor
axiosClient.interceptors.response.use(
  (response) =&gt; response.data,
  async (error) =&gt; {
    let message = '';
    const originalConfig = error.config;
    const code = error.response &amp;&amp; Number(error.response.status);
    
    switch (code) {
      case 401:
        if (error.response.data.error === RESPONSE_ERROR_MESSAGE.SIGNATURE_HAS_EXPIRED) {
          if (!isRefreshing) {
            isRefreshing = true;
            refreshTokensLoginApi().then(() =&gt; {
              const storage = useStorage();
              const accessToken = storage.getItem(StorageKeyEnum.AccessToken);
              onRefreshed(accessToken);
              
              isRefreshing = false;
              refreshSubscribers = [];
            });
          }

          const retryOrigReq = new Promise((resolve) =&gt; {
            subscribeTokenRefresh((token: string) =&gt; {
              // replace the expired token and retry
              originalConfig.headers.Authorization = `Bearer ${token}`;
              resolve(axiosClient(originalConfig));
            });
          });

          return retryOrigReq;
        }
        clearTokenRedirectLogin();

        message = ErrorHttpMessageEnum.Code401;
        break;
      case ...:
        break;
      default:
        message = ErrorHttpMessageEnum.Default;
    }
    return message;
  },
);

const subscribeTokenRefresh = (cb: (token: string) =&gt; void) =&gt; {
  refreshSubscribers.push(cb);
};

const onRefreshed = (token: string) =&gt; {
  refreshSubscribers.map((cb) =&gt; cb(token));
};

export default axiosClient;
" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> axios </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">axios</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  ErrorHttpMessageEnum, StorageKeyEnum, RESPONSE_ERROR_MESSAGE</span></span>
<span class="line"><span style="color: #F6F6F4">} </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">src/constant</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> { refreshTokensLoginApi, clearTokenRedirectLogin } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">src/helpers/auth</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F286C4">import</span><span style="color: #F6F6F4"> { useStorage } </span><span style="color: #F286C4">from</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">src/hooks/useStorage</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">let</span><span style="color: #F6F6F4"> isRefreshing </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F286C4">let</span><span style="color: #F6F6F4"> refreshSubscribers</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> ((</span><span style="color: #FFB86C; font-style: italic">token</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">string</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4">)[] </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> [];</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> axiosClient </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> axios.</span><span style="color: #62E884">create</span><span style="color: #F6F6F4">({</span></span>
<span class="line"><span style="color: #F6F6F4">  baseURL</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> process.env.</span><span style="color: #BF9EEE">PR_API_HOST</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  headers</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">Content-Type</span><span style="color: #DEE492">&#39;</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;</span><span style="color: #E7EE98">application/json</span><span style="color: #DEE492">&#39;</span><span style="color: #F6F6F4">,</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B">// Add a request interceptor</span></span>
<span class="line"><span style="color: #F6F6F4">axiosClient.interceptors.request.</span><span style="color: #62E884">use</span><span style="color: #F6F6F4">(</span></span>
<span class="line"><span style="color: #F6F6F4">  (</span><span style="color: #FFB86C; font-style: italic">config</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> storage </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">useStorage</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> accessToken </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> storage.</span><span style="color: #62E884">getItem</span><span style="color: #F6F6F4">(StorageKeyEnum.AccessToken);</span></span>
<span class="line"><span style="color: #F6F6F4">    </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (accessToken </span><span style="color: #F286C4">&amp;&amp;</span><span style="color: #F6F6F4"> config.headers) {</span></span>
<span class="line"><span style="color: #F6F6F4">      config.headers.Authorization </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">`Bearer </span><span style="color: #F286C4">${</span><span style="color: #F6F6F4">accessToken</span><span style="color: #F286C4">}</span><span style="color: #E7EE98">`</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> config;</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">  (</span><span style="color: #FFB86C; font-style: italic">error</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Promise</span><span style="color: #F6F6F4">.</span><span style="color: #62E884">reject</span><span style="color: #F6F6F4">(error)</span></span>
<span class="line"><span style="color: #F6F6F4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #7B7F8B">// Add a response interceptor</span></span>
<span class="line"><span style="color: #F6F6F4">axiosClient.interceptors.response.</span><span style="color: #62E884">use</span><span style="color: #F6F6F4">(</span></span>
<span class="line"><span style="color: #F6F6F4">  (</span><span style="color: #FFB86C; font-style: italic">response</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> response.data,</span></span>
<span class="line"><span style="color: #F6F6F4">  </span><span style="color: #F286C4">async</span><span style="color: #F6F6F4"> (</span><span style="color: #FFB86C; font-style: italic">error</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">let</span><span style="color: #F6F6F4"> message </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #DEE492">&#39;&#39;</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> originalConfig </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> error.config;</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> code </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> error.response </span><span style="color: #F286C4">&amp;&amp;</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">Number</span><span style="color: #F6F6F4">(error.response.status);</span></span>
<span class="line"><span style="color: #F6F6F4">    </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">switch</span><span style="color: #F6F6F4"> (code) {</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">case</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">401</span><span style="color: #F6F6F4">:</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (error.response.data.error </span><span style="color: #F286C4">===</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">RESPONSE_ERROR_MESSAGE</span><span style="color: #F6F6F4">.</span><span style="color: #BF9EEE">SIGNATURE_HAS_EXPIRED</span><span style="color: #F6F6F4">) {</span></span>
<span class="line"><span style="color: #F6F6F4">          </span><span style="color: #F286C4">if</span><span style="color: #F6F6F4"> (</span><span style="color: #F286C4">!</span><span style="color: #F6F6F4">isRefreshing) {</span></span>
<span class="line"><span style="color: #F6F6F4">            isRefreshing </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">true</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #62E884">refreshTokensLoginApi</span><span style="color: #F6F6F4">().</span><span style="color: #62E884">then</span><span style="color: #F6F6F4">(() </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">              </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> storage </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">useStorage</span><span style="color: #F6F6F4">();</span></span>
<span class="line"><span style="color: #F6F6F4">              </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> accessToken </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> storage.</span><span style="color: #62E884">getItem</span><span style="color: #F6F6F4">(StorageKeyEnum.AccessToken);</span></span>
<span class="line"><span style="color: #F6F6F4">              </span><span style="color: #62E884">onRefreshed</span><span style="color: #F6F6F4">(accessToken);</span></span>
<span class="line"><span style="color: #F6F6F4">              </span></span>
<span class="line"><span style="color: #F6F6F4">              isRefreshing </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">              refreshSubscribers </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> [];</span></span>
<span class="line"><span style="color: #F6F6F4">            });</span></span>
<span class="line"><span style="color: #F6F6F4">          }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">          </span><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> retryOrigReq </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4; font-weight: bold">new</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">Promise</span><span style="color: #F6F6F4">((</span><span style="color: #FFB86C; font-style: italic">resolve</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">            </span><span style="color: #62E884">subscribeTokenRefresh</span><span style="color: #F6F6F4">((</span><span style="color: #FFB86C; font-style: italic">token</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">string</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">              </span><span style="color: #7B7F8B">// replace the expired token and retry</span></span>
<span class="line"><span style="color: #F6F6F4">              originalConfig.headers.Authorization </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #E7EE98">`Bearer </span><span style="color: #F286C4">${</span><span style="color: #F6F6F4">token</span><span style="color: #F286C4">}</span><span style="color: #E7EE98">`</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">              </span><span style="color: #62E884">resolve</span><span style="color: #F6F6F4">(</span><span style="color: #62E884">axiosClient</span><span style="color: #F6F6F4">(originalConfig));</span></span>
<span class="line"><span style="color: #F6F6F4">            });</span></span>
<span class="line"><span style="color: #F6F6F4">          });</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">          </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> retryOrigReq;</span></span>
<span class="line"><span style="color: #F6F6F4">        }</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #62E884">clearTokenRedirectLogin</span><span style="color: #F6F6F4">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F6F6F4">        message </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> ErrorHttpMessageEnum.Code401;</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">break</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">case</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">...</span><span style="color: #F6F6F4">:</span></span>
<span class="line"><span style="color: #F6F6F4">        </span><span style="color: #F286C4">break</span><span style="color: #F6F6F4">;</span></span>
<span class="line"><span style="color: #F6F6F4">      </span><span style="color: #F286C4">default</span><span style="color: #F6F6F4">:</span></span>
<span class="line"><span style="color: #F6F6F4">        message </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> ErrorHttpMessageEnum.Default;</span></span>
<span class="line"><span style="color: #F6F6F4">    }</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #F286C4">return</span><span style="color: #F6F6F4"> message;</span></span>
<span class="line"><span style="color: #F6F6F4">  },</span></span>
<span class="line"><span style="color: #F6F6F4">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">subscribeTokenRefresh</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> (</span><span style="color: #62E884">cb</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> (</span><span style="color: #FFB86C; font-style: italic">token</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">string</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">void</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  refreshSubscribers.</span><span style="color: #62E884">push</span><span style="color: #F6F6F4">(cb);</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">const</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">onRefreshed</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> (</span><span style="color: #FFB86C; font-style: italic">token</span><span style="color: #F286C4">:</span><span style="color: #F6F6F4"> </span><span style="color: #97E1F1; font-style: italic">string</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> {</span></span>
<span class="line"><span style="color: #F6F6F4">  refreshSubscribers.</span><span style="color: #62E884">map</span><span style="color: #F6F6F4">((</span><span style="color: #FFB86C; font-style: italic">cb</span><span style="color: #F6F6F4">) </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #62E884">cb</span><span style="color: #F6F6F4">(token));</span></span>
<span class="line"><span style="color: #F6F6F4">};</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F286C4">export</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">default</span><span style="color: #F6F6F4"> axiosClient;</span></span>
<span class="line"></span></code></pre></div>



<p class="has-medium-font-size wp-block-paragraph"><strong>Kết luận</strong></p>



<p class="wp-block-paragraph">Có rất nhiều cách để chúng ta triển khai refresh token và phía trên là một trong số cách hiện tại của mình đang sử dụng để&nbsp;<code>refresh token</code> trong dự án. Cảm ơn mọi người đã dành thời gian để đọc 🙏</p>



<p class="wp-block-paragraph">Have a nice day!</p>
<p>The post <a href="https://blog.tomosia.com.vn/refresh-token-trong-axios-nhu-the-nao/">Refresh token trong Axios như thế nào?</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/refresh-token-trong-axios-nhu-the-nao/feed/</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
		<item>
		<title>Alpine.js là gì ?  Hãy Cùng tìm hiểu về cách sử dụng nào</title>
		<link>https://blog.tomosia.com.vn/alpine-js-la-gi-hay-cung-tim-hieu-ve-cach-su-dung-nao/</link>
					<comments>https://blog.tomosia.com.vn/alpine-js-la-gi-hay-cung-tim-hieu-ve-cach-su-dung-nao/#comments</comments>
		
		<dc:creator><![CDATA[quivo]]></dc:creator>
		<pubDate>Fri, 01 Dec 2023 02:35:52 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Alpine]]></category>
		<category><![CDATA[Laravel]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=1701</guid>

					<description><![CDATA[<p>Alpine.js là gì ? Alpine.js là một JavaScript framework nhẹ và dễ sử dụng, giúp bạn tạo ra&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/alpine-js-la-gi-hay-cung-tim-hieu-ve-cach-su-dung-nao/">Alpine.js là gì ?  Hãy Cùng tìm hiểu về cách sử dụng nào</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h3 id="alpine-js-la-gi" class="wp-block-heading">Alpine.js là gì ?</h3>



<p class="wp-block-paragraph">Alpine.js là một JavaScript framework nhẹ và dễ sử dụng, giúp bạn tạo ra các tương tác trực tiếp trên giao diện người dùng (UI) một cách dễ dàng và nhanh chóng mà không cần phải chạy npm, biên dịch tập lệnh, định cấu hình webpack. Nó là một giải pháp thay thế đơn giản và hiệu quả cho các frontend framework khác như Vue, React &amp; Angular. Hãy nghĩ về nó giống như&nbsp;<a href="https://tailwindcss.com/?ref=blog.tomosia.com.vn" target="_blank" rel="noreferrer noopener"><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-cyan-blue-color">Tailwind</mark></a>&nbsp;dành cho JavaScript.</p>



<p class="wp-block-paragraph"></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="563" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/11/social-1024x563.jpeg" alt="" class="wp-image-1704" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/11/social-1024x563.jpeg 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/social-300x165.jpeg 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/social-768x422.jpeg 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/social-380x209.jpeg 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/social-800x440.jpeg 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/social-1160x638.jpeg 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/11/social.jpeg 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h3 id="cach-su-dung" class="wp-block-heading">Cách sử dụng</h3>



<p class="wp-block-paragraph">Theo&nbsp;&nbsp;<a rel="noreferrer noopener" href="https://github.com/alpinejs/alpine?ref=blog.tomosia.com.vn" target="_blank">tài liệu của Alpine.js</a>&nbsp;, cú pháp của nó gần như được mượn hoàn toàn từ&nbsp;&nbsp;<a rel="noreferrer noopener" href="https://vuejs.org/?ref=blog.tomosia.com.vn" target="_blank">Vue.js</a>&nbsp;&nbsp;(và phần mở rộng&nbsp;&nbsp;<a rel="noreferrer noopener" href="https://angularjs.org/?ref=blog.tomosia.com.vn" target="_blank">Angular.js</a>&nbsp;), vì vậy nếu bạn đã biết một trong hai framework này thì bạn sẽ không phải mất nhiều thời gian để bắt đầu.</p>



<p class="wp-block-paragraph">Trong blog này, Chúng ta sẽ tìm hiểu cách sử dụng Alpine.js trong Laravel với hai ví dụ.</p>



<ol class="wp-block-list">
<li>Alpine.js CDN</li>



<li>Laravel Mix</li>
</ol>



<h4 id="su-dung-qua-cdn" class="wp-block-heading">Sử dụng qua CDN</h4>



<p class="wp-block-paragraph">Bạn chỉ cần thêm một thẻ script liên kết thư viện (xem ví dụ bên dưới). Rất đơn giản phải không nào! Bạn không cần phải biên dịch javascript hoặc cấu trúc dự án của mình theo bất kỳ cách cụ thể nào.</p>



<div class="wp-block-kevinbatdorf-code-block-pro alignfull cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:8.4296875px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="&lt;html&gt;
&lt;head&gt;
    &lt;script defer src=&quot;https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1 x-data=&quot;{ message: 'I ❤️ Alpine' }&quot; x-text=&quot;message&quot;&gt;&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F6F6F4">&lt;</span><span style="color: #F286C4">html</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">&lt;</span><span style="color: #F286C4">head</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;</span><span style="color: #F286C4">script</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">defer</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">src</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">&gt;&lt;/</span><span style="color: #F286C4">script</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">&lt;/</span><span style="color: #F286C4">head</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">&lt;</span><span style="color: #F286C4">body</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;</span><span style="color: #F286C4">h1</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">x-data</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">{ message: &#39;I ❤️ Alpine&#39; }</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">x-text</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">message</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">&gt;&lt;/</span><span style="color: #F286C4">h1</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">&lt;/</span><span style="color: #F286C4">body</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">&lt;/</span><span style="color: #F286C4">html</span><span style="color: #F6F6F4">&gt;</span></span></code></pre></div>



<h4 id="su-dung-qua-laravel-mix" class="wp-block-heading">Sử dụng qua Laravel mix</h4>



<p class="wp-block-paragraph">Trước tiên, bạn cần cài đặt Alpine js bằng lệnh npm bên dưới:</p>



<pre class="wp-block-code"><code>npm install alpinejs</code></pre>



<p class="wp-block-paragraph">Tiếp đó, bạn cần import vào <code><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-black-color"><strong>resources/js/app.js</strong></mark></code> file</p>



<pre class="wp-block-code"><code>import 'alpinejs';</code></pre>



<p class="wp-block-paragraph">Cuối cùng chỉ cần chạy lệnh</p>



<pre class="wp-block-code"><code>npm run dev</code></pre>



<p class="wp-block-paragraph">Bây giờ, bạn có thể sử dụng được alpine (nhớ thêm <strong>app.js</strong> vào blade view nhé)</p>



<pre class="wp-block-code"><code>&lt;script src="{{ mix('js/app.js') }}"&gt;&lt;/script&gt;</code></pre>



<p class="wp-block-paragraph">Cùng xem 1 ví dụ đơn giản nhé:</p>



<div class="wp-block-kevinbatdorf-code-block-pro alignfull cbp-has-line-numbers" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#f6f6f4;--cbp-line-number-width:16.859375px;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#333545;color:#ebebe6">JavaScript</span><span role="button" tabindex="0" data-code="&lt;div 
    x-data=&quot;{ show: false }&quot; 
    x-show=&quot;show&quot; 
    x-on:notify.window=&quot;() =&gt; { show = true; setTimeout(() =&gt; { show = false; }, 5000 ) }&quot;
    style=&quot;display:none;&quot;
    class=&quot;toast active&quot;
&gt;
    &lt;div class=&quot;toast-content&quot;&gt;
        &lt;i class=&quot;ti ti-check toast-icon&quot; x-on:click=&quot;show = false&quot;&gt;&lt;/i&gt;
        &lt;div class=&quot;message&quot;&gt;
            &lt;span class=&quot;message-title&quot;&gt;Ví dụ&lt;/span&gt;
            &lt;span class=&quot;message-content&quot;&gt;Ví dụ về alpine js&lt;/span&gt;
            &lt;span x-on:click=&quot;show = false&quot; class=&quot;close&quot;&gt;
                &lt;i class=&quot;ti ti-x&quot;&gt;&lt;/i&gt;
            &lt;/span&gt;
        &lt;/div&gt;
        &lt;div class=&quot;progress active&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;" style="color:#f6f6f4;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula-soft" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F6F6F4">&lt;</span><span style="color: #F286C4">div</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #62E884; font-style: italic">x-data</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">{ show: false }</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #62E884; font-style: italic">x-show</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">show</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #EE6666; font-style: italic; text-decoration: underline">x-on:notify.window=&quot;()</span><span style="color: #F6F6F4"> </span><span style="color: #EE6666; font-style: italic; text-decoration: underline">=&gt;</span><span style="color: #F6F6F4"> </span><span style="color: #F286C4">{</span><span style="color: #F6F6F4"> show </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">true</span><span style="color: #F6F6F4">; </span><span style="color: #62E884">setTimeout</span><span style="color: #F6F6F4">(() </span><span style="color: #F286C4">=&gt;</span><span style="color: #F6F6F4"> { show </span><span style="color: #F286C4">=</span><span style="color: #F6F6F4"> </span><span style="color: #BF9EEE">false</span><span style="color: #F6F6F4">; }, </span><span style="color: #BF9EEE">5000</span><span style="color: #F6F6F4"> ) </span><span style="color: #F286C4">}</span><span style="color: #DEE492">&quot;</span></span>
<span class="line"><span style="color: #E7EE98">    style=</span><span style="color: #DEE492">&quot;</span><span style="color: #EE6666; font-style: italic; text-decoration: underline">display:none;&quot;</span></span>
<span class="line"><span style="color: #F6F6F4">    </span><span style="color: #62E884; font-style: italic">class</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">toast active</span><span style="color: #DEE492">&quot;</span></span>
<span class="line"><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;</span><span style="color: #F286C4">div</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">class</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">toast-content</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">i</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">class</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">ti ti-check toast-icon</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">x-on</span><span style="color: #F286C4">:</span><span style="color: #62E884; font-style: italic">click</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">show = false</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">&gt;&lt;/</span><span style="color: #F286C4">i</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">div</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">class</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">message</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">            &lt;</span><span style="color: #F286C4">span</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">class</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">message-title</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">&gt;Ví dụ&lt;/</span><span style="color: #F286C4">span</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">            &lt;</span><span style="color: #F286C4">span</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">class</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">message-content</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">&gt;Ví dụ về alpine js&lt;/</span><span style="color: #F286C4">span</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">            &lt;</span><span style="color: #F286C4">span</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">x-on</span><span style="color: #F286C4">:</span><span style="color: #62E884; font-style: italic">click</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">show = false</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">class</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">close</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">                &lt;</span><span style="color: #F286C4">i</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">class</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">ti ti-x</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">&gt;&lt;/</span><span style="color: #F286C4">i</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">            &lt;/</span><span style="color: #F286C4">span</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;/</span><span style="color: #F286C4">div</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">        &lt;</span><span style="color: #F286C4">div</span><span style="color: #F6F6F4"> </span><span style="color: #62E884; font-style: italic">class</span><span style="color: #F286C4">=</span><span style="color: #DEE492">&quot;</span><span style="color: #E7EE98">progress active</span><span style="color: #DEE492">&quot;</span><span style="color: #F6F6F4">&gt;&lt;/</span><span style="color: #F286C4">div</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">    &lt;/</span><span style="color: #F286C4">div</span><span style="color: #F6F6F4">&gt;</span></span>
<span class="line"><span style="color: #F6F6F4">&lt;/</span><span style="color: #F286C4">div</span><span style="color: #F6F6F4">&gt;</span></span></code></pre></div>



<p class="wp-block-paragraph">Ở ví dụ trên, tôi có một component alert được phản ứng khi sự kiện <strong>notify</strong> được thực hiện thì sẽ hiển thị thông báo.</p>



<h3 id="ket-luan" class="wp-block-heading">Kết luận</h3>



<p class="wp-block-paragraph">Với sự đơn giản và gọn nhẹ của Alpine, tôi tin rằng đây sẽ là 1 trong số các giải pháp tốt nhất cho bạn trong một số trường hợp thay vì sử dụng các Js framework khác  như Vue hay React để rồi nhận thêm sự cồng kềnh, phức tạp mà chúng mang lại.</p>



<p class="wp-block-paragraph">Hiện tại, cùng với sự kết hợp với Tailwind, Livewire và Laravel, bộ tứ này đã và đang hình thành nên 1 ngăn xếp công nghệ mới được gọi là ngăn xếp TALL. Nếu tò mò bạn có thể xem tại <a rel="noreferrer noopener" href="https://blog.laravelvietnam.org/tall-stack/" data-type="link" data-id="https://blog.laravelvietnam.org/tall-stack/" target="_blank">blog.laravelvietnam</a>.</p>
<p>The post <a href="https://blog.tomosia.com.vn/alpine-js-la-gi-hay-cung-tim-hieu-ve-cach-su-dung-nao/">Alpine.js là gì ?  Hãy Cùng tìm hiểu về cách sử dụng nào</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/alpine-js-la-gi-hay-cung-tim-hieu-ve-cach-su-dung-nao/feed/</wfw:commentRss>
			<slash:comments>26</slash:comments>
		
		
			</item>
		<item>
		<title>Tips &#038; tricks javascript (P1)</title>
		<link>https://blog.tomosia.com.vn/tips-trick-javascript-p1/</link>
					<comments>https://blog.tomosia.com.vn/tips-trick-javascript-p1/#comments</comments>
		
		<dc:creator><![CDATA[admin_tomosia]]></dc:creator>
		<pubDate>Tue, 10 Oct 2023 01:52:49 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[javascript]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=1086</guid>

					<description><![CDATA[<p>1. Kiểm tra chẵn lẻ Bình thường mọi người hay check chẵn lẻ bằng cách này đúng không&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/tips-trick-javascript-p1/">Tips &#038; tricks javascript (P1)</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h3 id="1-kiem-tra-chan-le" class="wp-block-heading">1. Kiểm tra chẵn lẻ</h3>



<p class="wp-block-paragraph">Bình thường mọi người hay check chẵn lẻ bằng cách này đúng không</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const number = 123;

if (number % 2) console.log('even')
else console.log('odd')" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> number </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">123</span><span style="color: #F8F8F2">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">if</span><span style="color: #F8F8F2"> (number </span><span style="color: #FF79C6">%</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">) console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">even</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #FF79C6">else</span><span style="color: #F8F8F2"> console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">odd</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">)</span></span></code></pre></div>



<p class="wp-block-paragraph">Còn một cách khác để kiểm tra số đó là chẵn hay lẻ</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const number = 232;  

if (number &amp; 1) console.log(&quot;odd&quot;);
else console.log(&quot;even&quot;);" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> number </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">232</span><span style="color: #F8F8F2">;  </span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">if</span><span style="color: #F8F8F2"> (number </span><span style="color: #FF79C6">&amp;</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">) console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">odd</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">);</span></span>
<span class="line"><span style="color: #FF79C6">else</span><span style="color: #F8F8F2"> console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">even</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">);</span></span></code></pre></div>



<h3 id="2-su-dung-object-thay-vi-if-else-switch-case" class="wp-block-heading">2. Sử dụng object thay vì if-else, switch-case</h3>



<p class="wp-block-paragraph">Thay vì</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const day = new Date().getDay();

// switch case
switch (day) {
  case 1:
      console.log(&quot;Monday&quot;);
      break
  case 2:
      console.log(&quot;Tuesday&quot;);
      break
  case 3:
      console.log(&quot;Wednesday&quot;);
      break
  // other days
  default:
    console.log(&quot;Waiting For The Weekend.!&quot;);
}
  
// if else
if (day === 1) console.log(&quot;Monday&quot;)
else if (day === 2) console.log(&quot;Tuesday&quot;)
else if (day === 3) console.log(&quot;Wednesday&quot;)
// other days
else console.log(&quot;Waiting For The Weekend.!&quot;)" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> day </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6; font-weight: bold">new</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">Date</span><span style="color: #F8F8F2">().</span><span style="color: #50FA7B">getDay</span><span style="color: #F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4">// switch case</span></span>
<span class="line"><span style="color: #FF79C6">switch</span><span style="color: #F8F8F2"> (day) {</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">case</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">:</span></span>
<span class="line"><span style="color: #F8F8F2">      console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">Monday</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">);</span></span>
<span class="line"><span style="color: #F8F8F2">      </span><span style="color: #FF79C6">break</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">case</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">:</span></span>
<span class="line"><span style="color: #F8F8F2">      console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">Tuesday</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">);</span></span>
<span class="line"><span style="color: #F8F8F2">      </span><span style="color: #FF79C6">break</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">case</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">:</span></span>
<span class="line"><span style="color: #F8F8F2">      console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">Wednesday</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">);</span></span>
<span class="line"><span style="color: #F8F8F2">      </span><span style="color: #FF79C6">break</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #6272A4">// other days</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">default</span><span style="color: #F8F8F2">:</span></span>
<span class="line"><span style="color: #F8F8F2">    console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">Waiting For The Weekend.!</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">);</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"><span style="color: #F8F8F2">  </span></span>
<span class="line"><span style="color: #6272A4">// if else</span></span>
<span class="line"><span style="color: #FF79C6">if</span><span style="color: #F8F8F2"> (day </span><span style="color: #FF79C6">===</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">) console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">Monday</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #FF79C6">else</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">if</span><span style="color: #F8F8F2"> (day </span><span style="color: #FF79C6">===</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">) console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">Tuesday</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #FF79C6">else</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">if</span><span style="color: #F8F8F2"> (day </span><span style="color: #FF79C6">===</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">) console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">Wednesday</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">)</span></span>
<span class="line"><span style="color: #6272A4">// other days</span></span>
<span class="line"><span style="color: #FF79C6">else</span><span style="color: #F8F8F2"> console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">Waiting For The Weekend.!</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">)</span></span></code></pre></div>



<p class="wp-block-paragraph">thì</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const date = new Date().getDay();

const day = {
  0: &quot;Waiting For The Weekend.!&quot;,
  1: 'Monday',
  2: 'Tuesday',
  3: 'Wednesday',
  // other days
}

console.log(day[date]);" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> date </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6; font-weight: bold">new</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">Date</span><span style="color: #F8F8F2">().</span><span style="color: #50FA7B">getDay</span><span style="color: #F8F8F2">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> day </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #BD93F9">0</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">Waiting For The Weekend.!</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">,</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #BD93F9">1</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">Monday</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">,</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #BD93F9">2</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">Tuesday</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">,</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #BD93F9">3</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">Wednesday</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">,</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #6272A4">// other days</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(day[date]);</span></span></code></pre></div>



<h3 id="3-function-iife-immediately-invoked-function-expression" class="wp-block-heading">3. Function IIFE (Immediately Invoked Function Expression)</h3>



<p class="wp-block-paragraph">IIFE (Biểu thức hàm được gọi ngay lập tức) là một hàm JavaScript chạy ngay khi được xác định.</p>



<p class="wp-block-paragraph">Nó là một design pattern được gọi là&nbsp;<a href="https://developer.mozilla.org/en-US/docs/Glossary/Self-Executing_Anonymous_Function">Self-Executing Anonymous Function</a> gồm 2 phần chính:<br>&#8211; Đầu tiên là hàm ẩn danh với phạm vi từ vựng được bao bọc trong <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Grouping"><code>Grouping Operator</code></a>&nbsp;<code>()</code> . Điều này ngăn cản việc truy cập các biến trong thành ngữ IIFE cũng như làm ảnh hưởng dến phạm vi global.<br>&#8211; Phần thứ hai tạo biểu thức hàm được gọi ngay lập tức <code>()</code> qua đó công cụ JavaScript sẽ diễn giải hàm trực tiếp.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;link rel=&quot;icon&quot; href=&quot;/favicon.ico&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;HTML&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;/body&gt;
&lt;/html&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
  const userName = &quot;Đạt&quot;;
  
  ((name) =&gt; {
    alert(&quot;My name is &quot; + name);
  })(userName);
&lt;/script&gt;
" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">&lt;!</span><span style="color: #F8F8F2">DOCTYPE html</span><span style="color: #FF79C6">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">html</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">lang</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">en</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">head</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">    &lt;</span><span style="color: #FF79C6">meta</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">charset</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">UTF-8</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">    &lt;</span><span style="color: #FF79C6">link</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">rel</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">icon</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">href</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">/favicon.ico</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">    &lt;</span><span style="color: #FF79C6">meta</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">name</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">viewport</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">content</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">width=device-width, initial-scale=1.0</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">    &lt;</span><span style="color: #FF79C6">title</span><span style="color: #F8F8F2">&gt;HTML&lt;/</span><span style="color: #FF79C6">title</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;/</span><span style="color: #FF79C6">head</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">body</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;/</span><span style="color: #FF79C6">body</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">html</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">type</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">text/javascript</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  const userName = &quot;Đạt&quot;;</span></span>
<span class="line"><span style="color: #F8F8F2">  </span></span>
<span class="line"><span style="color: #F8F8F2">  ((name) =&gt; </span><span style="color: #FF79C6">{</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #50FA7B">alert</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">My name is </span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">+</span><span style="color: #F8F8F2"> name);</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #FF79C6">}</span><span style="color: #F8F8F2">)(userName);</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"></span></code></pre></div>



<h3 id="4-cache-array-length-trong-loop" class="wp-block-heading">4. Cache array.length trong loop</h3>



<p class="wp-block-paragraph">Tip này rất đơn giản và ảnh hưởng nhiều hơn đến hiệu suất khi xử lý các array lớn trong loop. Căn bản là, hầu như mọi người đều viết cái forto đồng bộ này dưới dạng một array:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="for (let i = 0; i &lt; array.length; i++) {
    console.log(array[i]);
}" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">for</span><span style="color: #F8F8F2"> (</span><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> i </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">; i </span><span style="color: #FF79C6">&lt;</span><span style="color: #F8F8F2"> array.length; i</span><span style="color: #FF79C6">++</span><span style="color: #F8F8F2">) {</span></span>
<span class="line"><span style="color: #F8F8F2">    console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array[i]);</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Nếu bạn làm việc với các array nhỏ hơn – không sao cả, nhưng nếu bạn xử lý các array lớn hơn, code này sẽ tính toán lại size của array trong mỗi vòng lặp của loop và sẽ gây ra gián đoạn nhỏ. Để tránh việc này xảy ra, bạn nên cache&nbsp;<code>array.length</code>&nbsp;trong một variable để dùng thay vì đụng tới&nbsp;<code>array.length</code>&nbsp;mọi lúc trong loop:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="var length = array.length;
for (let i = 0; i &lt; length; i++) {
    console.log(array[i]);
}" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">var</span><span style="color: #F8F8F2"> length </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> array.length;</span></span>
<span class="line"><span style="color: #FF79C6">for</span><span style="color: #F8F8F2"> (</span><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> i </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">; i </span><span style="color: #FF79C6">&lt;</span><span style="color: #F8F8F2"> length; i</span><span style="color: #FF79C6">++</span><span style="color: #F8F8F2">) {</span></span>
<span class="line"><span style="color: #F8F8F2">    console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array[i]);</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span></code></pre></div>



<p class="wp-block-paragraph">Để làm nó nhỏ lại, hãy viết code sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="for (let i = 0, length = array.length; i &lt; length; i++) {
    console.log(array[i]);
}" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">for</span><span style="color: #F8F8F2"> (</span><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> i </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">0</span><span style="color: #F8F8F2">, length </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> array.length; i </span><span style="color: #FF79C6">&lt;</span><span style="color: #F8F8F2"> length; i</span><span style="color: #FF79C6">++</span><span style="color: #F8F8F2">) {</span></span>
<span class="line"><span style="color: #F8F8F2">    console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array[i]);</span></span>
<span class="line"><span style="color: #F8F8F2">}</span></span></code></pre></div>



<h3 id="5-lay-item-cuoi-trong-array" class="wp-block-heading">5. Lấy item cuối trong array</h3>



<p class="wp-block-paragraph"><code>Array.prototype.slice(begin, end)</code> có thể cắt các array khi bạn đặt các argument begin và end. Nhưng nếu bạn không cài end argument, function này sẽ tự động gán giá trị lớn nhất cho array. Tôi nghĩ không nhiều người biết rằng function này có thể nhận giá trị âm, và nếu bạn set một số âm vào begin argument bạn sẽ nhận các element cuối cùng trong array:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="let array = [1, 2, 3, 4, 5, 6];
console.log(array.slice(-1)); // [6]
console.log(array.slice(-2)); // [5,6]
console.log(array.slice(-3)); // [4,5,6]" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> array </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> [</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">4</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">5</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">6</span><span style="color: #F8F8F2">];</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array.</span><span style="color: #50FA7B">slice</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">-</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">)); </span><span style="color: #6272A4">// [6]</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array.</span><span style="color: #50FA7B">slice</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">-</span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">)); </span><span style="color: #6272A4">// [5,6]</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array.</span><span style="color: #50FA7B">slice</span><span style="color: #F8F8F2">(</span><span style="color: #FF79C6">-</span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">)); </span><span style="color: #6272A4">// [4,5,6]</span></span></code></pre></div>



<h3 id="6-cat-array" class="wp-block-heading">6. <strong>Cắt array&nbsp;</strong></h3>



<p class="wp-block-paragraph">Phương pháp này có thể khóa size của array, rất hữu ích để xóa các elemnt của array dựa trên số element bạn muốn set. Ví dụ, nếu bạn có một array khoảng 10 element, nhưng bạn chỉ muốn lấy 5 element đầu tiên, bạn có thể cắt array, làm nó nhỏ lại bằng cách set&nbsp;<code>array.length&nbsp;=&nbsp;5</code>. Xem ví dụ sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="let array = [1, 2, 3, 4, 5, 6];
console.log(array.length); // 6
array.length = 3;
console.log(array.length); // 3
console.log(array); // [1,2,3]" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> array </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> [</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">4</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">5</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">6</span><span style="color: #F8F8F2">];</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array.length); </span><span style="color: #6272A4">// 6</span></span>
<span class="line"><span style="color: #F8F8F2">array.length </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array.length); </span><span style="color: #6272A4">// 3</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array); </span><span style="color: #6272A4">// [1,2,3]</span></span></code></pre></div>



<h3 id="7-gop-cac-array" class="wp-block-heading">7. Gộp các array</h3>



<p class="wp-block-paragraph">Nếu bạn cần gộp 2 array Bạn có thể dùng function&nbsp;<code>Array.concat()</code>:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
console.log(array1.concat(array2)); // [1,2,3,4,5,6];" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> array1 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> [</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">];</span></span>
<span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> array2 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> [</span><span style="color: #BD93F9">4</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">5</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">6</span><span style="color: #F8F8F2">];</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array1.</span><span style="color: #50FA7B">concat</span><span style="color: #F8F8F2">(array2)); </span><span style="color: #6272A4">// [1,2,3,4,5,6];</span></span></code></pre></div>



<p class="wp-block-paragraph">Tuy nhiên, function này không phù hợp để gộp các array lớn vì nó sẽ tiêu tốn nhiều dung lượng bằng cách tạo ra array mới. Trong trường hợp này, bạn có thể dùng&nbsp;<code>Array.push.apply(arr1,&nbsp;arr2)</code>&nbsp;để tạo array mới, nó sẽ gộp array thứ hai vào cái đầu tiên để giảm tiêu hao bộ nhớ:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
array1.push.apply(array1, array2)
console.log(array1); // [1,2,3,4,5,6];" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> array1 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> [</span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">];</span></span>
<span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> array2 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> [</span><span style="color: #BD93F9">4</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">5</span><span style="color: #F8F8F2">, </span><span style="color: #BD93F9">6</span><span style="color: #F8F8F2">];</span></span>
<span class="line"><span style="color: #F8F8F2">array1.push.</span><span style="color: #50FA7B">apply</span><span style="color: #F8F8F2">(array1, array2)</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(array1); </span><span style="color: #6272A4">// [1,2,3,4,5,6];</span></span></code></pre></div>



<h3 id="8-su-dung-set-de-nhan-cac-gia-tri-duy-nhat" class="wp-block-heading">8. Sử dụng SET để nhận các giá trị duy nhất</h3>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const arr = [10,10,20,20,30]; 
const new_arr = [...new Set(arr)]; 
  
console.log(new_arr); // [10, 20, 30]" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> arr </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> [</span><span style="color: #BD93F9">10</span><span style="color: #F8F8F2">,</span><span style="color: #BD93F9">10</span><span style="color: #F8F8F2">,</span><span style="color: #BD93F9">20</span><span style="color: #F8F8F2">,</span><span style="color: #BD93F9">20</span><span style="color: #F8F8F2">,</span><span style="color: #BD93F9">30</span><span style="color: #F8F8F2">]; </span></span>
<span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> new_arr </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> [</span><span style="color: #FF79C6">...</span><span style="color: #FF79C6; font-weight: bold">new</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">Set</span><span style="color: #F8F8F2">(arr)]; </span></span>
<span class="line"><span style="color: #F8F8F2">  </span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(new_arr); </span><span style="color: #6272A4">// [10, 20, 30]</span></span></code></pre></div>



<h3 id="9-clone-an-object" class="wp-block-heading">9. Clone an Object</h3>



<p class="wp-block-paragraph">Trong một dự án của tôi, tôi đã dính trường hợp gán giá trị một biến bằng một biến đã cho. Khi thay đổi biến đó nó làm thay đổi cả giá trị của biến đã cho kia. Tôi hiểu vì sao lỗi nhưng đã không biết cách fix cũng như không biết keyword của nó là gì để search. Có phải các bạn thường làm như này không:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="let obj1 = { a: 1, b: 2 };
let obj2 = obj1; // obj2 = { a: 1, b: 2 }

obj2.a = 3; // Gán lại giá trị a của obj2 = 3

console.log(obj1); // { a: 3, b: 2 } =&gt; Giá trị a của obj1 cũng thay đổi theo
console.log(obj2); // { a: 3, b: 2 }" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> obj1 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> { a</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">, b</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2"> };</span></span>
<span class="line"><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> obj2 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> obj1; </span><span style="color: #6272A4">// obj2 = { a: 1, b: 2 }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">obj2.a </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">; </span><span style="color: #6272A4">// Gán lại giá trị a của obj2 = 3</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(obj1); </span><span style="color: #6272A4">// { a: 3, b: 2 } =&gt; Giá trị a của obj1 cũng thay đổi theo</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(obj2); </span><span style="color: #6272A4">// { a: 3, b: 2 }</span></span></code></pre></div>



<p class="wp-block-paragraph">Dưới đây là một số cách fix nhé:</p>



<p class="wp-block-paragraph"><strong>Cách 1</strong>: Sử dụng Spread operator&nbsp;<code>{...}</code>&nbsp;hoặc&nbsp;<code>Object.assign()</code>.&nbsp;<strong><em>Issue:</em></strong>&nbsp;<code>Nested objects</code>&nbsp;vẫn có vấn đề trên.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="let obj1 = { a: 1, b: 2, c: { nested: 3 } };
let obj2 = { ...obj1 }; // obj2 = { a: 1, b: 2, c: { nested: 3 } }
let obj3 = Object.assign({}, obj1); // obj3 = { a: 1, b: 2, c: { nested: 3 } }

obj2.b = 3;
obj2.c.nested = 4;

console.log(obj1); // { a: 1, b: 2, c: { nested: 4 } } nested vẫn bị thay đổi này 🙂
console.log(obj2); // { a: 1, b: 3, c: { nested: 4 } } nested vẫn bị thay đổi này 🙂
console.log(obj3); // { a: 1, b: 2, c: { nested: 4 } } nested vẫn bị thay đổi này 🙂" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> obj1 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> { a</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">, b</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">, c</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> { nested</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2"> } };</span></span>
<span class="line"><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> obj2 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> { </span><span style="color: #FF79C6">...</span><span style="color: #F8F8F2">obj1 }; </span><span style="color: #6272A4">// obj2 = { a: 1, b: 2, c: { nested: 3 } }</span></span>
<span class="line"><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> obj3 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> Object.</span><span style="color: #50FA7B">assign</span><span style="color: #F8F8F2">({}, obj1); </span><span style="color: #6272A4">// obj3 = { a: 1, b: 2, c: { nested: 3 } }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">obj2.b </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">obj2.c.nested </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">4</span><span style="color: #F8F8F2">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(obj1); </span><span style="color: #6272A4">// { a: 1, b: 2, c: { nested: 4 } } nested vẫn bị thay đổi này 🙂</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(obj2); </span><span style="color: #6272A4">// { a: 1, b: 3, c: { nested: 4 } } nested vẫn bị thay đổi này 🙂</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(obj3); </span><span style="color: #6272A4">// { a: 1, b: 2, c: { nested: 4 } } nested vẫn bị thay đổi này 🙂</span></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Cách 2&nbsp;<code>(Recommended)</code></strong>: Sử dụng&nbsp;<code>JSON.stringify()</code>&nbsp;&amp;&nbsp;<code>JSON.parse()</code>.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="let obj1 = { a: 1, b: 2, c: { nested: 3 } };
let obj2 = JSON.parse(JSON.stringify(obj1)); // obj2 = { a: 1, b: 2, c: { nested: 3 } }

obj2.b = 3;
obj2.c.nested = 4;

console.log(obj1); // { a: 1, b: 2, c: { nested: 3 } } yêu chưa 😉😘
console.log(obj2); // { a: 1, b: 3, c: { nested: 4 } }" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> obj1 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> { a</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">1</span><span style="color: #F8F8F2">, b</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">2</span><span style="color: #F8F8F2">, c</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> { nested</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2"> } };</span></span>
<span class="line"><span style="color: #FF79C6">let</span><span style="color: #F8F8F2"> obj2 </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">JSON</span><span style="color: #F8F8F2">.</span><span style="color: #50FA7B">parse</span><span style="color: #F8F8F2">(</span><span style="color: #BD93F9">JSON</span><span style="color: #F8F8F2">.</span><span style="color: #50FA7B">stringify</span><span style="color: #F8F8F2">(obj1)); </span><span style="color: #6272A4">// obj2 = { a: 1, b: 2, c: { nested: 3 } }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">obj2.b </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">3</span><span style="color: #F8F8F2">;</span></span>
<span class="line"><span style="color: #F8F8F2">obj2.c.nested </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">4</span><span style="color: #F8F8F2">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(obj1); </span><span style="color: #6272A4">// { a: 1, b: 2, c: { nested: 3 } } yêu chưa 😉😘</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(obj2); </span><span style="color: #6272A4">// { a: 1, b: 3, c: { nested: 4 } }</span></span></code></pre></div>



<h3 id="10-lay-danh-sach-cac-khoa-va-gia-tri-tu-mot-object" class="wp-block-heading">10. Lấy danh sách các khóa và giá trị từ một object</h3>



<p class="wp-block-paragraph">Trong quá trình phát triển, có những lúc chúng ta chỉ cần lấy key hoặc chỉ value từ một đối tượng. Cả hai hàm dựng sẵn sau đây đều khá đơn giản:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="const vehicle = { brand: 'BWM', year: 2022, type: 'suv'};
//get keys
console.log(Object.keys(vehicle)); // [ 'brand', 'year', 'type' ]

//get values
console.log(Object.values(vehicle)); // [ 'BWM', 2022, 'suv' ]" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">const</span><span style="color: #F8F8F2"> vehicle </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> { brand</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">BWM</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">, year</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">2022</span><span style="color: #F8F8F2">, type</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">suv</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">};</span></span>
<span class="line"><span style="color: #6272A4">//get keys</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(Object.</span><span style="color: #50FA7B">keys</span><span style="color: #F8F8F2">(vehicle)); </span><span style="color: #6272A4">// [ &#39;brand&#39;, &#39;year&#39;, &#39;type&#39; ]</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4">//get values</span></span>
<span class="line"><span style="color: #F8F8F2">console.</span><span style="color: #50FA7B">log</span><span style="color: #F8F8F2">(Object.</span><span style="color: #50FA7B">values</span><span style="color: #F8F8F2">(vehicle)); </span><span style="color: #6272A4">// [ &#39;BWM&#39;, 2022, &#39;suv&#39; ]</span></span></code></pre></div>



<h3 id="ket-luan" class="wp-block-heading">Kết luận:</h3>



<p class="wp-block-paragraph">Ngôn ngữ nào cũng sẽ có rất nhiều tips &amp; tricks không riêng gì javascript. Trên đây là 10 tips &amp; tricks hay về javascript. Mong những tips &amp; tricks trên sẽ giúp ích được các bạn trong quá trình phát triển code của mình. Các bạn hãy comment một số tips &amp; tricks khác để chia sẻ cho mọi người nhé. Ủng hộ tôi bằng một lượt comment để ra tiếp phần 2 trong thời gian sắp tới nhé(nhưng chưa biết là bao giờ)</p>
<p>The post <a href="https://blog.tomosia.com.vn/tips-trick-javascript-p1/">Tips &#038; tricks javascript (P1)</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/tips-trick-javascript-p1/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title>Tạo custom input trong vuejs</title>
		<link>https://blog.tomosia.com.vn/tao-custom-input-trong-vuejs/</link>
					<comments>https://blog.tomosia.com.vn/tao-custom-input-trong-vuejs/#comments</comments>
		
		<dc:creator><![CDATA[admin_tomosia]]></dc:creator>
		<pubDate>Thu, 05 Oct 2023 06:25:11 +0000</pubDate>
				<category><![CDATA[VueJS]]></category>
		<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=342</guid>

					<description><![CDATA[<p>Có lẽ chúng ta đã quá quen thuộc với&#160;VueJS&#160;– một web framework vô cùng mạnh mẽ và “đẹp&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/tao-custom-input-trong-vuejs/">Tạo custom input trong vuejs</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Có lẽ chúng ta đã quá quen thuộc với&nbsp;<a rel="noreferrer noopener" href="https://vuejs.org/" target="_blank">VueJS</a>&nbsp;– một web framework vô cùng mạnh mẽ và “đẹp troai”.</p>



<p class="wp-block-paragraph">Trong đó, một trong những tính năng không thể thiếu đó là 2-way data binding, cụ thể là sử dụng v-model.</p>



<p class="wp-block-paragraph">Nếu chưa từng làm việc với vuejs thì mình sẽ giải thích một cách khái quát giúp bạn hiểu về v-model. Đây là một cách thức mà bạn hay dùng cho các form nhập liệu. Khi mà giá trị của các biến vừa dùng để hiển thị trên input, đồng thời khi người dùng nhập thì nó cũng tự động lưu vào biến đó. Vẫn hơi khó hiểu đúng không, vậy dưới đây là một ví dụ về v-model:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;template&gt;
  &lt;input type=&quot;text&quot; v-model=&quot;value&quot;/&gt;
  &lt;div&gt;giá trị nhập từ input: &lt;span style=&quot;color: red&quot;&gt;{{value}}&lt;/span&gt;&lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
export default {
  data() {
    return {
      value: ''
    }
  }
}
&lt;/script&gt;

// Input: Đây là giá trị được nhập từ input
// Output: giá trị nhập từ input: Đây là giá trị được nhập từ input" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">input</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">type</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">text</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">v-model</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">value</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">/&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">div</span><span style="color: #F8F8F2">&gt;giá trị nhập từ input: &lt;</span><span style="color: #FF79C6">span</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">style</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">color: red</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">&gt;</span><span style="color: #FF79C6">{</span><span style="color: #F8F8F2">{value}</span><span style="color: #FF79C6">}</span><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">span</span><span style="color: #F8F8F2">&gt;&lt;/</span><span style="color: #FF79C6">div</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">export default </span><span style="color: #FF79C6">{</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #50FA7B">data</span><span style="color: #F8F8F2">() {</span></span>
<span class="line"><span style="color: #F8F8F2">    return {</span></span>
<span class="line"><span style="color: #F8F8F2">      value: </span><span style="color: #E9F284">&#39;&#39;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">  }</span></span>
<span class="line"><span style="color: #FF79C6">}</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #6272A4">// Input: Đây là giá trị được nhập từ input</span></span>
<span class="line"><span style="color: #6272A4">// Output: giá trị nhập từ input: Đây là giá trị được nhập từ input</span></span></code></pre></div>



<p class="wp-block-paragraph">Dễ đúng không. Nhưng tùy vào dự án mà bạn cần tạo các custom input component mà trong đó cần phải xử lý 2-way data binding. Dưới đây là một số cách mà bạn có thể tự implement v-model:</p>



<ul class="wp-block-list">
<li>Watcher một biến local</li>



<li>Custom method để implement v-model</li>



<li>Sử dụng thuộc tính computer</li>



<li>&nbsp;Custom props và event</li>
</ul>



<h2 id="1-watcher-mot-bien-local" class="wp-block-heading">1. Watcher một biến local</h2>



<p class="wp-block-paragraph">Đây có lẽ là cách mọi người hay nghĩ tới nhất khi cần implement v-model cho component.</p>



<p class="wp-block-paragraph">Cách thực hiện đơn giản nhất là gồm những bước sau:</p>



<ul class="wp-block-list">
<li>chúng ta khai báo một props,</li>



<li>sau đó tạo một biến observable trong&nbsp;<code>data()</code>&nbsp;và khởi tạo giá trị là giá trị của props đã khai báo trước đó</li>



<li>Cuối cùng là sử dụng event để thông báo cho component cha, mục đích là để update giá trị props từ bên ngoài component.</li>
</ul>



<p class="wp-block-paragraph">Nói thì có vẻ trừu tượng vậy thôi, nhưng nhìn code là bạn sẽ thấy nó đơn giản như nào.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;!-- Tạo component CustomInput.vue --&gt;
&lt;template&gt;
  &lt;input type=&quot;text&quot; v-model=&quot;model&quot; /&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  props: ['modelValue'],
  data() {
    return {
      model: this.modelValue
    }
  },
  watch: {
    model(currentValue) {
      this.$emit('update:modelValue', currentValue)
    }
  }
}
&lt;/script&gt;

&lt;!-- Cách sử dụng --&gt;
&lt;template&gt;
  &lt;CustomInput v-model=&quot;text&quot; /&gt;
  &lt;div&gt;giá trị nhập từ input: &lt;span style=&quot;color: red&quot;&gt;{{text}}&lt;/span&gt;&lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
import CustomInput from './components/CustomInput.vue'
export default {
  components: { CustomInput },
  data() {
    return {
      text: ''
    }
  }
}
&lt;/script&gt;" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">&lt;!--</span><span style="color: #F8F8F2"> Tạo component CustomInput.vue </span><span style="color: #FF79C6">--&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">input</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">type</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">text</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">v-model</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">model</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> /&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">export default </span><span style="color: #FF79C6">{</span></span>
<span class="line"><span style="color: #F8F8F2">  props: [</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">modelValue</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">],</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #50FA7B">data</span><span style="color: #F8F8F2">() {</span></span>
<span class="line"><span style="color: #F8F8F2">    return {</span></span>
<span class="line"><span style="color: #F8F8F2">      model: </span><span style="color: #BD93F9; font-style: italic">this</span><span style="color: #F8F8F2">.modelValue</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">  },</span></span>
<span class="line"><span style="color: #F8F8F2">  watch: {</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #50FA7B">model</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">currentValue</span><span style="color: #F8F8F2">) {</span></span>
<span class="line"><span style="color: #F8F8F2">      </span><span style="color: #BD93F9; font-style: italic">this</span><span style="color: #F8F8F2">.</span><span style="color: #50FA7B">$emit</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">update:modelValue</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">, currentValue)</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">  }</span></span>
<span class="line"><span style="color: #FF79C6">}</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">&lt;!--</span><span style="color: #F8F8F2"> Cách sử dụng </span><span style="color: #FF79C6">--&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #8BE9FD; font-style: italic">CustomInput</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">v-model</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">text</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> /&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">div</span><span style="color: #F8F8F2">&gt;giá trị nhập từ input: &lt;</span><span style="color: #FF79C6">span</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">style</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">color: red</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">&gt;</span><span style="color: #FF79C6">{</span><span style="color: #F8F8F2">{text}</span><span style="color: #FF79C6">}</span><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">span</span><span style="color: #F8F8F2">&gt;&lt;/</span><span style="color: #FF79C6">div</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">import CustomInput from &#39;./components/CustomInput.vue&#39;</span></span>
<span class="line"><span style="color: #F8F8F2">export default </span><span style="color: #FF79C6">{</span></span>
<span class="line"><span style="color: #F8F8F2">  components: { CustomInput },</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #50FA7B">data</span><span style="color: #F8F8F2">() {</span></span>
<span class="line"><span style="color: #F8F8F2">    return {</span></span>
<span class="line"><span style="color: #F8F8F2">      text: </span><span style="color: #E9F284">&#39;&#39;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">  }</span></span>
<span class="line"><span style="color: #FF79C6">}</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span></code></pre></div>



<h2 id="2-custom-method-de-implement-v-model" class="wp-block-heading">2. Custom method để implement v-model</h2>



<p class="wp-block-paragraph">Nếu sử dụng watcher ảnh hưởng tới hiệu năng của ứng dụng. Vậy cách 2 này sẽ tận dụng event @input có sẵn của input native và tạo một custom method trong component của chúng ta.</p>



<p class="wp-block-paragraph">Chúng ta sẽ truyền giá trị của input tới component cha thông qua emit một event, mục đích cũng là để có thể cập nhật props từ bên ngoài component.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;!-- Tạo component CustomInput.vue --&gt;
&lt;template&gt;
  &lt;input
    :value=&quot;modelValue&quot;
    @input=&quot;$emit('update:modelValue', $event.target.value)&quot;
  /&gt;
&lt;/template&gt;
&lt;script&gt;
export default {
  props: ['modelValue'],
  emits: ['update:modelValue']
}
&lt;/script&gt;

&lt;!-- Cách sử dụng --&gt;
&lt;template&gt;
  &lt;CustomInput v-model=&quot;text&quot; /&gt;
  &lt;div&gt;giá trị nhập từ input: &lt;span style=&quot;color: red&quot;&gt;{{ text }}&lt;/span&gt;&lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
import CustomInput from './components/CustomInput.vue'
export default {
  components: { CustomInput },
  data() {
    return {
      text: ''
    }
  }
}
&lt;/script&gt;" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">&lt;!--</span><span style="color: #F8F8F2"> Tạo component CustomInput.vue </span><span style="color: #FF79C6">--&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">input</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF5555; font-style: italic; text-decoration: underline">:value=&quot;modelValue&quot;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF5555; font-style: italic; text-decoration: underline">@input=&quot;$emit(&#39;update:modelValue&#39;,</span><span style="color: #F8F8F2"> </span><span style="color: #FF5555; font-style: italic; text-decoration: underline">$event.target.value)&quot;</span></span>
<span class="line"><span style="color: #F8F8F2">  /&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">export default </span><span style="color: #FF79C6">{</span></span>
<span class="line"><span style="color: #F8F8F2">  props: [</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">modelValue</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">],</span></span>
<span class="line"><span style="color: #F8F8F2">  emits: [</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">update:modelValue</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">]</span></span>
<span class="line"><span style="color: #FF79C6">}</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">&lt;!--</span><span style="color: #F8F8F2"> Cách sử dụng </span><span style="color: #FF79C6">--&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #8BE9FD; font-style: italic">CustomInput</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">v-model</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">text</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> /&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">div</span><span style="color: #F8F8F2">&gt;giá trị nhập từ input: &lt;</span><span style="color: #FF79C6">span</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">style</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">color: red</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">&gt;</span><span style="color: #FF79C6">{</span><span style="color: #F8F8F2">{ text }</span><span style="color: #FF79C6">}</span><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">span</span><span style="color: #F8F8F2">&gt;&lt;/</span><span style="color: #FF79C6">div</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">import CustomInput from &#39;./components/CustomInput.vue&#39;</span></span>
<span class="line"><span style="color: #F8F8F2">export default </span><span style="color: #FF79C6">{</span></span>
<span class="line"><span style="color: #F8F8F2">  components: { CustomInput },</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #50FA7B">data</span><span style="color: #F8F8F2">() {</span></span>
<span class="line"><span style="color: #F8F8F2">    return {</span></span>
<span class="line"><span style="color: #F8F8F2">      text: </span><span style="color: #E9F284">&#39;&#39;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">  }</span></span>
<span class="line"><span style="color: #FF79C6">}</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span></code></pre></div>



<pre class="wp-block-verse">Lưu ý: Đối với Vue3, thuộc tính value được đổi tên thành modelValue và tên của event input được đổi thành update:modelValue</pre>



<h2 id="3-su-dung-thuoc-tinh-computer" class="wp-block-heading">3. Sử dụng thuộc tính computer</h2>



<p class="wp-block-paragraph">Một cách khác nữa để implement v-model trong một custom component đó là sử dụng getter và setter của computed.</p>



<p class="wp-block-paragraph">Bạn có thể định nghĩa một thuộc tính computed, sau đó:</p>



<ul class="wp-block-list">
<li>Implement một getter để trả về value của thuộc tính đó.</li>



<li>Một setter để emit một input event tới component cha</li>
</ul>



<p class="wp-block-paragraph">Cụ thể cách viết code như sau:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;!-- Tạo component CustomInput.vue --&gt;
&lt;template&gt;
  &lt;input v-model=&quot;value&quot; /&gt;
&lt;/template&gt;&lt;script&gt;
export default {
  props: ['modelValue'],
  computed: {
    value: {
      get() {
        return this.modelValue
      },
      set(value) {
        this.$emit('update:modelValue', value)
      }
    }
  }
}
&lt;/script&gt;

&lt;!-- Cách sử dụng --&gt;
&lt;template&gt;
  &lt;CustomInput v-model=&quot;text&quot; /&gt;
  &lt;div&gt;giá trị nhập từ input: &lt;span style=&quot;color: red&quot;&gt;{{ text }}&lt;/span&gt;&lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
import CustomInput from './components/CustomInput.vue'
export default {
  components: { CustomInput },
  data() {
    return {
      text: ''
    }
  }
}
&lt;/script&gt;" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">&lt;!--</span><span style="color: #F8F8F2"> Tạo component CustomInput.vue </span><span style="color: #FF79C6">--&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">input</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">v-model</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">value</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> /&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;&lt;</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">export default </span><span style="color: #FF79C6">{</span></span>
<span class="line"><span style="color: #F8F8F2">  props: [</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">modelValue</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">],</span></span>
<span class="line"><span style="color: #F8F8F2">  computed: {</span></span>
<span class="line"><span style="color: #F8F8F2">    value</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> {</span></span>
<span class="line"><span style="color: #F8F8F2">      </span><span style="color: #50FA7B">get</span><span style="color: #F8F8F2">() {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #FF79C6">return</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9; font-style: italic">this</span><span style="color: #F8F8F2">.modelValue</span></span>
<span class="line"><span style="color: #F8F8F2">      },</span></span>
<span class="line"><span style="color: #F8F8F2">      </span><span style="color: #50FA7B">set</span><span style="color: #F8F8F2">(</span><span style="color: #FFB86C; font-style: italic">value</span><span style="color: #F8F8F2">) {</span></span>
<span class="line"><span style="color: #F8F8F2">        </span><span style="color: #BD93F9; font-style: italic">this</span><span style="color: #F8F8F2">.</span><span style="color: #50FA7B">$emit</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">update:modelValue</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">, value)</span></span>
<span class="line"><span style="color: #F8F8F2">      }</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">  }</span></span>
<span class="line"><span style="color: #FF79C6">}</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6">&lt;!--</span><span style="color: #F8F8F2"> Cách sử dụng </span><span style="color: #FF79C6">--&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #8BE9FD; font-style: italic">CustomInput</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">v-model</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">text</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> /&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">div</span><span style="color: #F8F8F2">&gt;giá trị nhập từ input: &lt;</span><span style="color: #FF79C6">span</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">style</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">color: red</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2">&gt;</span><span style="color: #FF79C6">{</span><span style="color: #F8F8F2">{ text }</span><span style="color: #FF79C6">}</span><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">span</span><span style="color: #F8F8F2">&gt;&lt;/</span><span style="color: #FF79C6">div</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">import CustomInput from &#39;./components/CustomInput.vue&#39;</span></span>
<span class="line"><span style="color: #F8F8F2">export default </span><span style="color: #FF79C6">{</span></span>
<span class="line"><span style="color: #F8F8F2">  components: { CustomInput },</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #50FA7B">data</span><span style="color: #F8F8F2">() {</span></span>
<span class="line"><span style="color: #F8F8F2">    return {</span></span>
<span class="line"><span style="color: #F8F8F2">      text: </span><span style="color: #E9F284">&#39;&#39;</span></span>
<span class="line"><span style="color: #F8F8F2">    }</span></span>
<span class="line"><span style="color: #F8F8F2">  }</span></span>
<span class="line"><span style="color: #FF79C6">}</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span></code></pre></div>



<h2 id="4-custom-props-va-event" class="wp-block-heading">4. Custom props và event</h2>



<p class="wp-block-paragraph">Vì prop và event mặc định của v-model của Vue3 là <code>modelValue</code> và <code>update:modelValue </code>. Tuy nhiên chúng ta có thể biến đổi tên của nó bằng cách truyền đối số cho v-model</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;!-- Component cha --&gt;
&lt;CustomInput v-model:title=&quot;text&quot; /&gt;" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">&lt;!--</span><span style="color: #F8F8F2"> Component cha </span><span style="color: #FF79C6">--&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #8BE9FD; font-style: italic">CustomInput</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B; font-style: italic">v-model</span><span style="color: #FF79C6">:</span><span style="color: #50FA7B; font-style: italic">title</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">text</span><span style="color: #E9F284">&quot;</span><span style="color: #F8F8F2"> /&gt;</span></span></code></pre></div>



<p class="wp-block-paragraph">Trong trường hợp này, component con sẽ nhận một prop <code>title</code> và một emit một sự kiện <code>update:title</code> để cập nhật lại giá trị ở component cha</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="&lt;!-- CustomInput.vue --&gt;
&lt;template&gt;
  &lt;input
    type=&quot;text&quot;
    :value=&quot;title&quot;
    @input=&quot;$emit('update:title', $event.target.value)&quot;
  /&gt;
&lt;/template&gt;
&lt;script&gt;
export default {
  props: ['title'],
  emits: ['update:title']
}
&lt;/script&gt;" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">&lt;!--</span><span style="color: #F8F8F2"> CustomInput.vue </span><span style="color: #FF79C6">--&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">  &lt;</span><span style="color: #FF79C6">input</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #50FA7B; font-style: italic">type</span><span style="color: #FF79C6">=</span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">text</span><span style="color: #E9F284">&quot;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF5555; font-style: italic; text-decoration: underline">:value=&quot;title&quot;</span></span>
<span class="line"><span style="color: #F8F8F2">    </span><span style="color: #FF5555; font-style: italic; text-decoration: underline">@input=&quot;$emit(&#39;update:title&#39;,</span><span style="color: #F8F8F2"> </span><span style="color: #FF5555; font-style: italic; text-decoration: underline">$event.target.value)&quot;</span></span>
<span class="line"><span style="color: #F8F8F2">  /&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">template</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span>
<span class="line"><span style="color: #F8F8F2">export default </span><span style="color: #FF79C6">{</span></span>
<span class="line"><span style="color: #F8F8F2">  props: [</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">title</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">],</span></span>
<span class="line"><span style="color: #F8F8F2">  emits: [</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">update:title</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">]</span></span>
<span class="line"><span style="color: #FF79C6">}</span></span>
<span class="line"><span style="color: #F8F8F2">&lt;/</span><span style="color: #FF79C6">script</span><span style="color: #F8F8F2">&gt;</span></span></code></pre></div>



<h3 id="ket-luan" class="wp-block-heading">Kết luận</h3>



<p class="wp-block-paragraph">Trên đây là một số cách để bạn implement v-model trong một component tùy chỉnh mà bạn tự tạo.Tương tự bạn cũng có thể làm với một số type khác của input như radio, checkbox,&#8230;</p>



<p class="wp-block-paragraph">VueJS với ưu điểm nhanh, gọn, nhẹ và tùy biến cao, nên mình nghĩ ngoài những cách trên, sẽ còn nhiều cách khác nữa.</p>



<p class="wp-block-paragraph">Bạn còn nghĩ ra cách nào khác để implement v-model cho component nữa không? Để lại ý kiến bình luận bên dưới nhé. Mình cũng đang đón chờ đây.</p>
<p>The post <a href="https://blog.tomosia.com.vn/tao-custom-input-trong-vuejs/">Tạo custom input trong vuejs</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/tao-custom-input-trong-vuejs/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>Sentry.io cho người mới bắt đầu (Vuejs)</title>
		<link>https://blog.tomosia.com.vn/sentry-io-cho-nguoi-moi-bat-dau-vuejs/</link>
					<comments>https://blog.tomosia.com.vn/sentry-io-cho-nguoi-moi-bat-dau-vuejs/#comments</comments>
		
		<dc:creator><![CDATA[admin_tomosia]]></dc:creator>
		<pubDate>Wed, 04 Oct 2023 07:08:05 +0000</pubDate>
				<category><![CDATA[VueJS]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[sentry]]></category>
		<guid isPermaLink="false">https://blog.tomosia.com.vn/?p=259</guid>

					<description><![CDATA[<p>Tình huống Bạn đang phát triển một ứng dụng web Vue.js lớn với khách hàng cũng lớn không&#8230;</p>
<p>The post <a href="https://blog.tomosia.com.vn/sentry-io-cho-nguoi-moi-bat-dau-vuejs/">Sentry.io cho người mới bắt đầu (Vuejs)</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/10/sentry-and-vue-js-1024x375.png" alt="" class="wp-image-260" style="width:680px;height:249px" width="680" height="249" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/10/sentry-and-vue-js-1024x375.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/sentry-and-vue-js-300x110.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/sentry-and-vue-js-768x282.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/sentry-and-vue-js-380x139.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/sentry-and-vue-js-800x293.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/sentry-and-vue-js-1160x425.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/sentry-and-vue-js.png 1200w" sizes="auto, (max-width: 680px) 100vw, 680px" /></figure>



<h2 id="tinh-huong" class="wp-block-heading">Tình huống</h2>



<p class="wp-block-paragraph">Bạn đang phát triển một ứng dụng web Vue.js lớn với khách hàng cũng lớn không kém. Một ngày đẹp trời nào đó, khách hàng gửi cho bạn 1 bug mà thoạt nhìn có vẻ đơn giản, tuy nhiên, bạn không thể tái hiện lỗi này trong môi trường phát triển của mình, và bạn không có thông tin rõ ràng về tình trạng lỗi. Trong tình huống này, bạn có thể sử dụng <a href="https://sentry.io/welcome/"><strong>Sentry</strong></a> để giúp xác định và giải quyết lỗi một cách hiệu quả. Vậy cùng mình đi tìm hiểu xem Sentry là gì mà lại lợi hại như vậy.</p>



<h2 id="sentry-la-gi" class="wp-block-heading">Sentry là gì</h2>



<p class="wp-block-paragraph">Sentry là một dịch vụ quản lý lỗi (error tracking) và giám sát (monitoring) phần mềm được sử dụng để theo dõi và ghi lại các lỗi và sự cố trong ứng dụng phần mềm. Sentry giúp các nhà phát triển và nhóm phát triển phát hiện, theo dõi, và khắc phục lỗi một cách hiệu quả. Dịch vụ này có thể được tích hợp vào các ứng dụng web và ứng dụng di động để ghi lại thông tin về lỗi, crash, và sự cố xảy ra trong quá trình chạy ứng dụng</p>



<h2 id="loi-ich-cua-sentry" class="wp-block-heading">Lợi ích của Sentry</h2>



<ul class="wp-block-list">
<li><strong>Ghi lại lỗi tự động:</strong> Sentry có thể được tích hợp vào mã của bạn để tự động ghi lại thông tin về lỗi mỗi khi nó xảy ra trong môi trường sản xuất. Điều này cho phép bạn nhận được thông báo ngay khi có sự cố xảy ra.</li>



<li><strong>Thông tin về lỗi chi tiết:</strong> Sentry không chỉ ghi lại lỗi mà còn cung cấp thông tin chi tiết về nguồn gốc của lỗi, ngăn chặn lỗi, và cách lỗi xảy ra. Điều này giúp bạn dễ dàng xác định vị trí và nguyên nhân gây ra lỗi.</li>



<li><strong>Theo dõi thời gian thực:</strong> Sentry cung cấp một giao diện quản lý web cho phép bạn theo dõi lỗi trong thời gian thực và tìm hiểu về tần suất và ngữ cảnh xảy ra lỗi.</li>



<li><strong>Cung cấp stack trace:</strong> Sentry có khả năng tạo ra stack trace, cho phép bạn xem các hàm và dòng mã cụ thể liên quan đến lỗi. Điều này giúp bạn tìm ra lỗi trong mã của bạn.</li>



<li><strong>Thông báo ngay lập tức: </strong>Sentry có thể bắn thông báo qua mail, SMS, &#8230;</li>
</ul>



<h2 id="setup-sentry-cho-vue2" class="wp-block-heading">Setup Sentry cho Vue2</h2>



<p class="wp-block-paragraph">Muốn sử dụng Sentry trước tiên bạn cần có tài khoản, vào <a href="https://sentry.io/signup/ ">https://sentry.io/signup/ </a> để đăng ký tài khoản.</p>



<p class="wp-block-paragraph">Sau khi đăng ký xong và đăng nhập thành công giao diện sẽ hiển thị như sau: </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="624" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-02-at-18.18.11-1-1024x624.png" alt="" class="wp-image-297" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-02-at-18.18.11-1-1024x624.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-02-at-18.18.11-1-300x183.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-02-at-18.18.11-1-768x468.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-02-at-18.18.11-1-1536x936.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-02-at-18.18.11-1-2048x1248.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-02-at-18.18.11-1-380x232.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-02-at-18.18.11-1-800x487.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-02-at-18.18.11-1-1160x707.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-02-at-18.18.11-1.png 2728w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Okay, tiếp theo thì ấn vào nút <strong>Create project</strong>, trong phần tạo đấy, vì mình đang hướng dẫn cho vue nên hãy chọn vuejs, nhập tên project và nhấn nút <strong>Create Project</strong>: </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="701" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-11.47.06-1024x701.png" alt="" class="wp-image-290" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-11.47.06-1024x701.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-11.47.06-300x205.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-11.47.06-768x526.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-11.47.06-1536x1051.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-11.47.06-2048x1402.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-11.47.06-380x260.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-11.47.06-800x547.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-11.47.06-1160x794.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-11.47.06.png 2300w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Vậy là chúng ta đã tạo xong <em>Project</em> trên <strong>Sentry</strong>, bước tiếp theo là lấy <strong>Client Keys (DSN)</strong> để có thể tích hợp vào dự án vuejs, từ <strong>Menu -&gt; Projects -&gt; Chọn Project bạn vừa tạo -&gt; Chọn cài đặt bên góc trên bên phải -&gt; Client Keys (DSN)</strong></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="653" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-12.11.51-1024x653.png" alt="" class="wp-image-294" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-12.11.51-1024x653.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-12.11.51-300x191.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-12.11.51-768x490.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-12.11.51-1536x979.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-12.11.51-2048x1306.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-12.11.51-380x242.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-12.11.51-800x510.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-12.11.51-1160x740.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-03-at-12.11.51.png 2296w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Cài đặt <strong>Sentry</strong> cho vue: <strong><code><mark style="background-color:#e9ecef" class="has-inline-color has-black-color">npm install @sentry/cli</mark></code></strong></p>



<p class="wp-block-paragraph">Trong <strong>main.js</strong>, khởi tạo <em>Sentry.init</em> với <em>dsn</em> chính là <strong>Client Keys (DSN)</strong> bạn lấy ở bên trên: </p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282A36"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" data-code="import Vue from 'vue'
import App from './App.vue'
import * as Sentry from &quot;@sentry/vue&quot;

Vue.config.productionTip = false

Sentry.init({
  Vue,
  dsn: &quot;https://51b9f7xxxxxxxx.ingest.sentry.io/45059xxxxxxxxx&quot;
});

new Vue({
  render: h =&gt; h(App),
}).$mount('#app')
" style="color:#F8F8F2;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki dracula" style="background-color: #282A36" tabindex="0"><code><span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> Vue </span><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">vue</span><span style="color: #E9F284">&#39;</span></span>
<span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> App </span><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">./App.vue</span><span style="color: #E9F284">&#39;</span></span>
<span class="line"><span style="color: #FF79C6">import</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">*</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">as</span><span style="color: #F8F8F2"> Sentry </span><span style="color: #FF79C6">from</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">@sentry/vue</span><span style="color: #E9F284">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">Vue.config.productionTip </span><span style="color: #FF79C6">=</span><span style="color: #F8F8F2"> </span><span style="color: #BD93F9">false</span></span>
<span class="line"></span>
<span class="line"><span style="color: #F8F8F2">Sentry.</span><span style="color: #50FA7B">init</span><span style="color: #F8F8F2">({</span></span>
<span class="line"><span style="color: #F8F8F2">  Vue,</span></span>
<span class="line"><span style="color: #F8F8F2">  dsn</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #E9F284">&quot;</span><span style="color: #F1FA8C">https://51b9f7xxxxxxxx.ingest.sentry.io/45059xxxxxxxxx</span><span style="color: #E9F284">&quot;</span></span>
<span class="line"><span style="color: #F8F8F2">});</span></span>
<span class="line"></span>
<span class="line"><span style="color: #FF79C6; font-weight: bold">new</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">Vue</span><span style="color: #F8F8F2">({</span></span>
<span class="line"><span style="color: #F8F8F2">  </span><span style="color: #50FA7B">render</span><span style="color: #FF79C6">:</span><span style="color: #F8F8F2"> </span><span style="color: #FFB86C; font-style: italic">h</span><span style="color: #F8F8F2"> </span><span style="color: #FF79C6">=&gt;</span><span style="color: #F8F8F2"> </span><span style="color: #50FA7B">h</span><span style="color: #F8F8F2">(App),</span></span>
<span class="line"><span style="color: #F8F8F2">}).</span><span style="color: #50FA7B">$mount</span><span style="color: #F8F8F2">(</span><span style="color: #E9F284">&#39;</span><span style="color: #F1FA8C">#app</span><span style="color: #E9F284">&#39;</span><span style="color: #F8F8F2">)</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Các bước đã xong, giờ bạn đã có thể test <strong>Sentry</strong> bằng cách tạo thử 1 <em>Exception</em>.</p>



<p class="wp-block-paragraph">Khi 1 <em>Exception</em> được thực thi, <strong>Sentry</strong> sẽ bắt và trả về cho bạn thông tin xoay quanh <em>Exception</em> đó: </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="545" src="http://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38-1024x545.png" alt="" class="wp-image-376" srcset="https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38-1024x545.png 1024w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38-300x160.png 300w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38-768x409.png 768w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38-1536x817.png 1536w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38-2048x1089.png 2048w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38-380x202.png 380w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38-800x426.png 800w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38-1160x617.png 1160w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38-1920x1024.png 1920w, https://blog.tomosia.com.vn/wp-content/uploads/2023/10/Screenshot-2023-10-04-at-12.19.38.png 2722w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h2 id="tong-ket" class="wp-block-heading">Tổng kết</h2>



<p class="wp-block-paragraph">Trên đây là thông tin cũng như hướng dẫn cơ bản để có thể tích hợp <strong>Sentry</strong> vào dự án vuejs, còn rất nhiều tính năng hay ho nữa như filter bằng trình duyệt, hỗ trợ source map trong việc gửi thông tin stack trace của exception, &#8230;. bạn hãy tự mình khám phá thêm nhé, mình đã làm được và mình tin bạn cũng sẽ làm được. Hẹn gặp lại ở bài tiếp theo</p>
<p>The post <a href="https://blog.tomosia.com.vn/sentry-io-cho-nguoi-moi-bat-dau-vuejs/">Sentry.io cho người mới bắt đầu (Vuejs)</a> appeared first on <a href="https://blog.tomosia.com.vn">Tomoshare</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.tomosia.com.vn/sentry-io-cho-nguoi-moi-bat-dau-vuejs/feed/</wfw:commentRss>
			<slash:comments>11</slash:comments>
		
		
			</item>
	</channel>
</rss>
