Bài viết này mình sẽ giới thiệu vài cách truy cập vào VPS nha, cách cuối là xịn mịn nhất 😋
#### Cách 1: Dùng username và password để truy cập vào VPS
Khi mình mua VPS, thường nhà cung cấp sẽ gửi cho mình username và password qua email. Để truy cập vào VPS thì mình:
```
ssh ten_dang_nhap@ip_vps
# Ví dụ:
ssh root@103.173.66.22
```
Tiếp theo nhập mật khẩu là có thể truy cập vào được rồi.
📌 Mặc định SSH sử dụng cổng 22. Nếu VPS của bạn dùng cổng khác, thêm `-p`:
```
ssh root@103.173.66.22 -p 8686
```
---
#### Cách 2: Dùng SSH key thay vì mật khẩu
Thay vì mỗi lần truy cập vào VPS phải nhập username & password, bạn có thể dùng SSH key — **an toàn và tiện hơn nhiều**.
👉 Cách tạo SSH key trên máy cá nhân mình có bài viết ở [đây](http://localhost:3000/ssh-key-trong-github), bạn có thể xem qua trước.
Sau khi bạn đã tạo SSH key (gồm 2 file: `id_rsa` và `id_rsa.pub`, hoặc tên tuỳ bạn đặt), tiếp theo là copy **public key** (`.pub`) lên VPS để xác thực.
##### 🛠 Cách 1: Copy public key bằng `ssh-copy-id` (nhanh, gọn)
```
ssh-copy-id -i ~/.ssh/id_rsa.pub root@ip_vps
```
Sau khi nhập mật khẩu lần đầu, key của bạn sẽ được copy vào file `authorized_keys` trên VPS.
##### 🛠 Cách 2: Thêm SSH key thủ công (khi VPS chưa có gì sẵn)
**Bước 1:** Trên máy bạn, copy nội dung public key:
```
cat ~/.ssh/id_rsa.pub
```
→ Copy toàn bộ dòng hiển thị.
**Bước 2:** Đăng nhập vào VPS bằng mật khẩu:
```
ssh root@ip_vps
```
**Bước 3:** Trên VPS, tạo thư mục `.ssh` nếu chưa có:
```
mkdir -p ~/.ssh && chmod 700 ~/.ssh
```
**Bước 4:** Tạo và mở file `authorized_keys`:
```
nano ~/.ssh/authorized_keys
```
→ Dán public key, nhấn `Ctrl + O` để lưu, `Ctrl + X` để thoát.
**Bước 5:** Kiểm tra lại file chứa đúng key chưa:
```
cat ~/.ssh/authorized_keys
```
→ Nếu thấy key vừa dán là xong!
✅ Giờ thì bạn có thể SSH mà không cần gõ mật khẩu nữa:
```
ssh root@ip_vps
```
📌 Nếu private key không nằm ở vị trí mặc định (`~/.ssh/id_rsa`), bạn dùng:
```
ssh -i /duong_dan_den/id_rsa root@ip_vps
```
---
#### 🔥 Cách 3: Dùng Visual Studio Code (VSCode) để kết nối vào VPS
Cách này khá tiện lợi và mình đang dùng để quản lý & chỉnh sửa trực tiếp trên VPS thông qua **VSCode + extension Remote - SSH**. Bạn không cần dùng terminal mà vẫn thao tác được như local 😄
---
**Bước 1: Cài đặt extension Remote - SSH**
- Mở VSCode
- Nhấn `Ctrl + Shift + X` để vào Extensions
- Tìm “Remote - SSH” và cài đặt

> 📎 Shortcut cài nhanh: [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh)
---
**Bước 2: Cấu hình SSH trong file `config`**
- Nhấn `Ctrl + P`, dán `~/.ssh/config` để mở nhanh file config.
- Thêm thông tin VPS của bạn như sau:
```
Host TenVpsCuaBan # đặt tên tuỳ ý để hiển thị trong VSCode
HostName 103.173.66.22 # IP VPS
User root # User để SSH
IdentityFile ~/.ssh/id_rsa # đường dẫn tới private key
```
📌 Nếu VPS dùng cổng SSH khác, thêm dòng:
```
Port 8686
```
---
**Bước 3: Kết nối tới VPS từ VSCode**
- Nhấn `Ctrl + Shift + P`
- Gõ: `Remote-SSH: Connect to Host...`
- Chọn `TenVpsCuaBan` bạn vừa cấu hình
- VSCode sẽ mở ra một cửa sổ mới bên trong môi trường VPS 🎉
---
#### ✨ Lợi ích khi dùng Remote - SSH với VSCode
- **Tiết kiệm thời gian** khi chỉnh sửa file trực tiếp trên VPS.
- **Tận dụng full tính năng** của VSCode như Prettier, ESLint, Git...
- **Không cần terminal**, thao tác nhanh như đang làm việc local.
💡 Đây là cách mình dùng mỗi ngày để làm việc với project trên VPS. Cực kỳ tiện và chuyên nghiệp luôn!
---
Hy vọng bài viết này giúp bạn làm chủ việc kết nối và quản lý VPS nhanh hơn nha 🚀
Bài này mình cùng tìm hiểu Class trong Javascript nó là gì nhé. Từ khi được giới thiệu trong ES6 (ECMAScript 2015), Class đã trở thành một tính năng không thể thiếu khi phát triển ứng dụng JavaScript theo hướng đối tượng.
### 1. Class là gì?
Class trong JavaScript giúp ra các object có cùng thuộc tinh và phương thức nhất định. Đồng thời tăng tính tái sử dụng code và dễ dàng quản lí hơn
### 2. Tạo Class đầu tiên với `User`
Chúng ta ví dụ tạo 1 class `User`, đại diện cho một người dùng trong hệ thống nhé.
```js
class User {
constructor(hoTen) {
// this.name: thuộc tính của đối tượng
// hoTen: tham số truyền vào constructor
this.name = hoTen;
}
// Phương thức
greet() {
return `Xin chào, tôi là ${this.name}`;
}
}
// Tạo các object (instance) từ class User
const user1 = new User("TuPV");
const user2 = new User("VuPV");
console.log(user1.greet()); // Xin chào, tôi là TuPV
console.log(user2.greet()); // Xin chào, tôi là VuPV
```
### 3. Kế thừa Class với `Admin`
Giả sử bạn muốn có một loại người dùng đặc biệt — đó là **Admin** (quản trị viên). Admin cũng là một `User`, nhưng có thêm quyền hạn (permissions) riêng biệt. Lúc này, bạn có thể **kế thừa** từ class `User` để tạo ra class `Admin`.
```js
class Admin extends User {
constructor(hoTen, quyenHan) {
super(hoTen); // Gọi constructor của class cha (User) để khởi tạo this.name
this.role = "Admin";
this.permissions = quyenHan; // mảng các quyền
}
// Ghi đè phương thức greet
greet() {
// Gọi lại phương thức greet của class cha và mở rộng nội dung
return (
super.greet() +
` Tôi là quản trị viên có quyền: ${this.permissions.join(", ")}`
);
}
// Thêm phương thức riêng của Admin
hasPermission(quyen) {
return this.permissions.includes(quyen);
}
}
const admin1 = new Admin("Admin TuPV", ["create", "delete", "update"]);
console.log(admin1.greet()); // Xin chào, tôi là Admin TuPV Tôi là quản trị viên có quyền: create, delete, update
console.log(admin1.hasPermission("delete")); // true
console.log(admin1.hasPermission("read")); // false
```
### 4. Tại sao nên sử dụng Class và kế thừa?
- **Tổ chức mã nguồn tốt hơn** khi ứng dụng phát triển lớn.
- **Tái sử dụng code** thông qua kế thừa (`extends`).
- **Dễ mở rộng**: Bạn có thể thêm nhiều loại người dùng khác nhau (Admin, Editor, Guest...) mà không phải viết lại logic chung.
---
### 5. Tổng kết
- `class` là cách hiện đại để định nghĩa và tổ chức code theo hướng đối tượng.
- `constructor` giúp khởi tạo dữ liệu ban đầu cho đối tượng.
- `extends` dùng để kế thừa từ class khác, tái sử dụng logic và mở rộng chức năng.
- `super()` gọi constructor của class cha.
---
## 6. Từ khóa `static` là gì?
Từ khóa `static` trong JavaScript được dùng để định nghĩa **phương thức hoặc thuộc tính tĩnh** cho class. Điều đặc biệt là các phương thức/thuộc tính `static` **không thể gọi từ object (instance)**, mà phải gọi **trực tiếp từ class**.
Nói cách khác, `static` thường được dùng cho các hành vi hoặc thông tin chung mà không phụ thuộc vào dữ liệu cụ thể của một object.
### Ví dụ:
```js
class User {
constructor(hoTen) {
this.name = hoTen;
}
greet() {
return `Xin chào, tôi là ${this.name}`;
}
test() {
console.log(this.sayHello());
}
// Phương thức static
static sayHello() {
return "Chào mừng bạn đến với hệ thống!";
}
}
const userTest = new User("TuPV");
console.log(userTest.greet()); // Xin chào, tôi là TuPV
console.log(User.sayHello()); // Chào mừng bạn đến với hệ thống!
console.log(userTest.sayHello()); // error: userTest.sayHello is not a function
console.log(User.test()); // error: User.test is not a function vì static method không thể gọi từ instance
```
> ⚠️ Gọi `userTest.sayHello()` sẽ bị lỗi vì `sayHello` là static method và chỉ có thể gọi qua class `User`.
---
Bạn cũng có thể dùng `static` trong class con kế thừa từ class cha:
```js
class Admin extends User {
constructor(hoTen, quyenHan) {
super(hoTen);
this.permissions = quyenHan;
}
greet() {
return `${super.greet()} Tôi là Admin.`;
}
static getRoleName() {
return "Quản trị viên";
}
}
console.log(Admin.getRoleName()); // Quản trị viên
```
---
## 7. Khi nào nên dùng `static`?
- Khi bạn muốn tạo các **hàm tiện ích dùng chung**, ví dụ như kiểm tra dữ liệu đầu vào, định dạng chuỗi, kiểm tra quyền truy cập...
- Khi bạn không cần truy cập đến `this` của từng object.
- Khi bạn muốn lưu **biến dùng chung** cho toàn bộ class, không gắn với từng instance.
---
## 8. Tổng kết thêm
| Khái niệm | Mô tả |
| ------------- | ---------------------------------------------------------------- |
| `class` | Tạo khuôn mẫu đối tượng |
| `constructor` | Hàm khởi tạo khi tạo object |
| `extends` | Kế thừa từ class khác |
| `super()` | Gọi constructor hoặc method của class cha |
| `static` | Định nghĩa phương thức/thuộc tính tĩnh, dùng trực tiếp qua class |
---
Hy vọng sau bài viết này bạn đã hiểu rõ hơn về cách sử dụng `class`, `extends`, `super` và `static` trong JavaScript một cách thực tiễn và dễ hiểu.
Hé looooo, lâu ngày quá blog mốc mêu rùi 😄, mới hôm nào kêu viết bài mở hàng 2025 mà vèo cái đã tháng 4 rồi nhanh thiệt á =))). Hứa trong tháng 4 này sẽ hoàn thành các bài viết hướng dẫn deploy dự án cơ bản như Html Css hoặc React, Next hay Node lên VPS như thế nào và thiết kế CI, CD qua Github Action luôn nhen
Mình hay mua tên miền ở [Inet](https://inet.vn/). Các bạn có thể lựa các tên miền tiết kiệm chi phí để demo như .fun, .id.vn...
#### VPS
**VPS** ở Việt Nam thì mình có thể mua ở [TinoHost](https://tinohost.com/) hay [ZHost](http://zhost.vn/) chỗ nào cũng được miễn các bạn thấy i tín là quất thui. Cấu hình thì để demo thì mình có thể chọn gói thấp nhất của các nhà cung cấp để demo cũng tẹc ga rồi, còn thực tế thì tuỳ dự án mình chọn gói cho phù hợp nha
Khi mua VPS mọi người chọn version cho Ubuntu hỗ trợ lâu dài tí nha có dạng LTS (Long term support) có thể lên trang này check [wiki.ubuntu.com/Releases](https://wiki.ubuntu.com/Releases) vì khi không để ý sẽ chọn nhầm sang version cũ như `23.04` không còn support nữa thì khi chạy `sudo apt-get update` sẽ không được. Lỡ chọn rồi thì fix bằng command ở dưới để update lại version Ubuntu nhé
```
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
sudo sed -i -re 's/([a-z]{2}.)?archive.ubuntu.com|security.ubuntu.com/old-releases.ubuntu.com/g' /etc/apt/sources.list
sudo apt-get update && sudo apt-get dist-upgrade
```
#### DNS
**DNS** là viết tắt của (Domain Name System) giúp mình dịch từ tên miền sang địa chỉ IP. Thay vì gõ `103.173.66.24:3002` thì mình gõ `phamvantu.com` thì đó là nhờ vào DNS dịch giúp mình đó
> **Note:** Để biết được trang web đang dùng địa chỉ ip nào thì chỉ cần ping domain_name là được. Ví dụ `ping phamvantu.com` thì nó ra địa chỉ ip là 103.173.66.24 thì đây là địa chỉ IP của trang web mình đó. Nhưng các bạn vào thì có thể ra trang Nginx thì đó là do mình không config nó. Tuỳ trang có hay không chứ không phải lúc nào nhập ip cũng ra trang web tương ứng nhen
#### Tên miền
Khi mua 1 tên miền thì họ sẽ cho 2 thông tin mình chỉnh sửa
- Name Server: Sửa máy chủ DSN của tên miền (Mặc định sẽ dùng máy chủ của nhà bán tên miền)
- Bản ghi DNS: Sửa các bảng ghi DNS của tên miền theo máy chủ đó
> Tên miền dùng máy chủ DNS nào thì phải sửa các bản ghi DNS theo máy chủ DNS đó
Ví dụ mình có 1 tên miền `setkeo.fun` ở inet thì mặt định DNS của inet như sau
- 
Mình muốn kết nối IP VPS của mình vào tên miền `setkeo.fun` thì thông thường sẽ chỉnh sửa bảng ghi, chứ không đụng vào DNS cứ để mặc định đó luôn nha
Một tên miền có thể tạo vô số subdomain(sub.example.com, sub2.example.com, sub3.example.com...), nên 1 tên miền có thể dùng có nhiều dự án khác nhau
Khi mình change A record thì nên chờ 1 phút rồi mới truy cập lại, không thì có thể bị dính cache vài ngày
Có thể dùng `https://dnschecker.org/`, `https://www.whois.com/whois` để kiểm tra máy chủ dns, bản ghi dns, người đăng ký tên miền...
Bài tiếp theo mình sẽ SSH vào VPS nha
Bài tiếp theo của nextjs thì mình sẽ nói về routing trong nextjs nhé. Mình sẽ nói ngắn gọn nhất có thể để ae đọc hình dung dứt liền luôn nha
### Basic
Thư mục **sign-in** có file **page.tsx** thì nextjs sẽ tạo ra đường dẫn webapp là **/sign-in**
Trong thư mục phải có file page.tsx là bắt buộc nhen, file chỉ mục đường dẫn của nó luôn á.
### Nested routes
Ví dụ mình muốn url **/course/lession** trong đó course sẽ là dynamic, mong muốn get value tên khoá học về để dùng query data. Thì mình sẽ tạo folder như sau **[ course]/lesson/page.tsx** thì nó sẽ có url kiểu kiểu như **react-course/lesson?slug=bai-1** đương nhiên `react-course` là động nha. Case này gọi là `dynamic segment`. Segment ae hiểu như là thư mục cho dễ hiểu hen. Tóm cái quần lại là mục đích để lấy params ra để xử lý gọi api hay gì đó…À đừng để 2 thư mục [dynamic] cùng cấp nha ae, vì nextjs không hiểu mình vô thằng nào á nè
Còn nếu ae muốn url cứng hết thì đơn giản chỉ cần tạo **folder course** trong folder course có **folder lession** thì url sẽ luôn luôn là course/lession nè. Nếu không đúng url course/lession thì nó bắn lẹ page 404 liền. Cái này thì đơn giản hơn nhiều hen
### Group
Group thì nó không tạo ra routing nha ae. Mục đích là để gom nhóm các routing liên quan vào chung ví dụ mình sẽ tạo thư mục **(dashboard)** thì sẽ không tạo ra route /dashboard đâu nha nếu vào thì ra 404 liền đoá
### Catch-all Segments
Ví dụ mình có folder như sau **shop/[…shop]** thì nó sẽ chấp nhận các route như /sign-in/a, /sign-in/b nếu vào /sign-in thì sẽ báo not-found liền
### Catch-all Segments
Ví dụ mình có folder như sau **shop/[…shop]** thì nó sẽ chấp nhận các route như /sign-in/a, /sign-in/b và bao gồm luôn route /sign-in luôn nha. Khác mỗi cái trên vậy thui đó
### Params
Thông thường là dynamic routes. Như ví dụ ở trên có thư mục **[** **course]/lesson** có url là **react-course/lesson** thì params là 1 object có key là course value là “react-course”. Dễ chưa =))
### SearchParams
Thường là những query ở trên URL ví dụ **lesson?slug=html-css.** Thì slug chính là searchParams. Log ra thì nó cũng là 1 object có key là slug value là ‘html-css”
Sương sương vậy thui đó, dễ ăn, dễ trúng thưởng 😜. Hẹn ae bài tiếp theo nhennn
Say hi những người ae, TuPV comeback đây kaka lâu ngày quá rồi để cái blog mốc mêuuuu luôn á kaka. Thôi thì NextJs ra vừa ra bản [NextJs15 RC](https://nextjs.org/blog/next-15-rc) cách đây mấy ngày thì thôi đu theo luôn cho nó trending tí nhen.
Bài này sẽ là khởi đầu cho những bài về NextJs về sau nha, viết vội chứ chuẩn bị cưới vợ rồi dí lắm 😆. Bài viết này mình sẽ list những cách dùng font như từ google fonts, font weight, variables, multiple fonts, local fonts, tailwind fonts…gét goooooo 😜
Mình sẽ để font ở trong layout.tsx nha. Mặc định cài nextJs đã có next/font và tối ưu luôn cho mình sẵn rồi. Nếu mình dùng link cdn để nhúng font vào thì cũng được okie, nhưng load lần tiên sẽ bị kiểu như nháy 1 phát từ font mặc định sang font mình nhúng cdn, nó chưa apply vô kịp á gọi là [Layout Shift](https://web.dev/articles/cls) cho nó bài bản 😁. Nhưng mà nếu dùng font google có sẵn những font trong này [Font Google](https://fonts.google.com/variablefonts) thì sẽ tự động cache lại bất kỳ font nào ở đây.
```
import { Manrope, Roboto } from "next/font/google"
// Khai báo
const manrope = Manrope({ subsets: ["latin"] })
const roboto = Roboto({ subsets: ["latin"], weight: ["400", "500"]})
// Sử dụng
{children}
Pham Van Tu
```
Tuỳ font mà nó sẽ yêu cầu weight hay không nhưng thường nên note những font weight mình dùng trong hệ thống và 1 mảng nha. `Vì nếu không truyền là nó auto lấy hết font weight của chữ đó có luôn á :D`, thừa quá không cần nè.
Dự án sẽ có nhiều font thì mình nên đặt tên biến cho từng font
```
// Khai báo variable
export const manrope = Manrope({ subsets: ["latin"], variable: "--font-manrope", })
export const roboto = Roboto({ subsets: ["latin"], variable: "--font-roboto", weight: ["400", "500"], })
// Khai báo variable sử dụng
{children}
// Defined common
body {
font-family: var(--font-manrope)
}
p {
font-family: var(--font-roboto)
}
```
**Vậy sử dụng biến trong Tailwind Css như thế nào và ví dụ như font không có trên google font thì sao nào 👇**
Tại file tailwind.config khai báo giúp mình như sau
```
theme: {
extend: {
fontFamily: {
primary: ["var(--font-manrope)"],
secondary: ["var(--font-roboto)"],
},
},
}
```
Khi sử dụng thì đơn giản là `
` là có font manrope rồi nè
Vậy sử dụng local font dưới máy thì ae bỏ font trong app rồi ae dùng như dưới nha, dùng thì tương như ở trên mình có thể để class trong thẻ body sét fontName.classname là okela rồi
```
import localFont from "next/font/local";
// Nếu mà font có 1 style thôi thì ae có thể để string thôi cũng được cho ngắn gọn
const dm_sans = localFont({
src: "" || [
{
path: "",
weight: "",
style: "italic",
},
],
display: "swap",
});
```
**Note** : Ae nên sẽ tạo ra 1 file fonts.ts chẳng hạn rồi defined font các kiểu gì đó ra rồi import dùng ở layout cho okie hơn hi. Cái này nextjs khuyến cáo nên zị á 😇 cho nó smooth performer hơn
Đến đây là hết gòi, hóng bài sau cùng TuPV nhen, buy mọi ngườiiiiiiii 🤭
Hello mấy ae 2024, lâu lâu lại chọt 1 bài lên gọi là có tính duy trì viết bài chút 😆. Bài viết này mình sẽ làm giới thiệu responsive hình ảnh, video theo tỉ lệ tuỳ thích nhé, gét goooo
Khi chúng ta làm theo thiết kế có sẵn khung nào đó thì khoẻ rồi hen, có nhiêu xét nhiêu thui không thành vấn đề nhưng đôi khi người ta muốn hiển thị video, hình ảnh theo tỉ lệ 16: 9 hoặc 4:3 hoặc tỉ lệ nào đó…thì các bạn xem ví dụ ở dưới nha
Sau khi ae biết Postman là gì và dùng cơ bản được qua bài viết [Sử dụng Postman cho test API](https://phamvantu.com/su-dung-postman-cho-test-api) thì bài viết này mình thử viết script cho nó xem sao nhé. Gét gooooo 🤪
Bài biết này mình sẽ viết script để nó tự động hoá lưu access_token và refresh_token vào environment của Postman nhé.
Tương tự như bài trước thì mình sẽ set access_token cho foder cha cho nó nhé nhưng token thì mình sẽ lấy từ trong environment ra nha
Nếu như cách thủ công thì sau khi login xong trả về access_token và refresh_token rồi mình copy set nó vào biến environment để các api các cần token để dùng.
Trường hợp access_token hết hạn mau quá thì mình phải gọi request refresh_token để nhận được access_token mới rồi copy sang nữa thì hơi… 😳. Hên là Postman hỗ trợ mình viết script để nó tự động hoá cho mình luôn ròiiii
Ae sẽ thấy 2 loại Script là Pre-request Script và Test thì tương ứng đó là script chạy trước khi gửi và script chạy sau khi gửi. Cái này viết theo ngôn ngữ Javascript nhưng viết theo format Postman.
Khi mình chạy request login xong thì nó kiểm tra thử status có bằng 200 hông, nếu bằng thì đoạn test mình okie chạy thành công. Mình sẽ lấy response từ Postman ra bằng cách `pm.response.json()` và sẽ set vào các giá trị mong muốn environment thuii
Tương tự các request khác thì ae muốn set vào environment thì làm tương tự như trên còn không thì chỉ cần check status = 200 là thành công gòiii
Trường hợp access_token hết hạn thì mình gọi request refresh-access-token để cập nhật lại access_token mới trong environment và những api khác cần token để gửi lên headers vẫn mướt mườn mượt luôn 😝
Hết ròi!!!. Hy vọng bài viết này giúp ae khỏi copy gán gán như mình lúc trước nữa ahihi 😁
Chắc ae cũng khá quen với công cụ Postman dùng để test api rồi. Nhưng mình cũng cũng nói sơ lại cho ae newbie có đọc bài này thì cũng hình dung nó là gì nha. Thường ae backend code api thì họ test ở trên này luôn cho tiện thay vì gọi javascript hay axios bla bla để test xem okie hay chưa. Hoặc như ae nhận 1 list api từ BE và ae muốn check lại api trả về đúng định dạng ae muốn hay chưa thì dùng postman test luôn.
Ae có thể download phiên bản phù hợp tại link chính thức của nó [tại đây](https://www.postman.com/) nhé.
Bên sidebar có `Collection` nằm đầu tiên. Nó như 1 folder vậy á, thường mình sẽ chia mỗi dự án là mỗi Collection riêng.
Vd mình có 2 api get list user và api create user như bên dưới
Ở đây mình đang bị lặp `https://reqres.in/api` nên mình sẽ tạo 1 biến để dùng lại. Thì biến ở Postman gọi là environment. Ae có thể chọn bên sidebar dưới mục Collection rồi tạo mới 1 environment để dùng nha.
Và khi tạo xong qua lại 2 request lúc nãy mình cập nhật lại `https://reqres.in/api thành {{host}}` rồi test lại nhé, nhớ là mình phải set environment bên góc phải trên cho nó rồi mới chạy được nha.
Trường hợp request cần truyền token lên thì mình set bên tab Authorization và chọn type tương ứng với bên api setup nha, thường sẽ là Bearer Token như hình bên dưới.
Sau khi gọi request này thì bên Headers sẽ gửi lên key là Authorization với value là token mình set ứng lúc nãy
Vậy lỡ có nhiều request cần token gửi lên thì sao. Vậy thì mình set token ở folder cha của nó rồi các request con kế thừa là được nha. Như hình dưới mình Folder cha có Type là Bear Token và set token cho nó luôn
Ở request con mình chỉ cần chọn Authorization là `Inherit auth from parent` là okie rồi
Hy vọng bài viết này sẽ giúp ae hiểu và sử dụng được công cụ này hiệu quà nhé. Bài viết sau mình sẽ giới thiệu viết script tự động hoá Postman nha. Ví dự như khi login xong thì mình có được accessToken và refreshToken và nó sẽ tự động lưu vào các biến môi trường của mình rồi mình đem đi gán cho các request cần truyền token lên header chẳng hạn nha hehe. Baiiiiii 😝
Hi ae, bài viết này xem tìm xem thử cái nào chiếm dung lượng nhiều trong project của mình và optimized nó nhé.
Nếu mình chỉ build thông thường thì khó mà phát hiện ra cái gì chiếm nhiều dung lượng, mình dùng vite nên ở đây mình giới thiệu công cụ [Rollup Plugin Visualizer](http://npmjs.com/package/rollup-plugin-visualizer), thằng Vite được build dựa trên thằng Rollup nên dùng nó để phân tích file build nhé, nếu anh ae dùng webpack thì có package [webpack-bundle-analyzer](https://www.npmjs.com/package/webpack-bundle-analyzer) tương tự nhé.
Khi mình chạy build nó sẽ cho xuất ra cho mình 1 file chỉ số stats.html cùng cấp với package.json của mình luôn. Ae có thể mở lên và theo dõi chỉ số nhé và check thử cái nào cần tối ưu được thì mình tối ưu cho nhẹ nha. Dùng cái nào thì import cái đó thôi thay vì import cả thư viện vào -> Tree-shaking
Sau khi tối ưu thì ae có thể tự check kích thước file build của mình nhé đương nhiên là nhỏ hơn rồi 😝, và load lại file stats tận hưởng thành quả nha 🥰
Hy vọng bài viết này sẽ giúp ae phân tích file build và có thể tối ưu nó lại nhé với giao diện theo dõi trực quan okie luôn
Nghĩ lễ 2/9 sâu quá ghé blog chém gió xíu xíu chớ ae quên mình mất 😆
Đôi lúc ae code nhiều nhưng quên mất lúc build để deploy lên production thì không biết ra sao hè. Ae mở package.json và xem thử lệnh build như thế nào nhé
dev: để ae dev quen quá rồi :v
build: chạy vite build
preview: chạy file build của chúng ta. Ví dụ sau khi build ra được file js, html, css thì preview nó sẽ chạy cái những file này lên cho chúng ta
Sau khi build nó sẽ nằm trong thư mục dist của chúng ta, gzip trên hình là nó 1 file nén lại từ file build ra. Và khi deploy lên server là nó sẽ deploy thằng dist này lên chứ mình không deploy cái src nha.
Mục src để mình code thoiii. Để chạy bản production lên thì chạy yarn preview. Mọi người sẽ thấy toàn bộ app mình sẽ dồn toàn bộ javascript thành 1 file nặng gần 200 kiB sau khi đã được nén. Sau khi chạy yarn preview thì ae chọn tab network và chọn tab js, nó sẽ chạy mỗi cái file js sau khi build ra
Trường hợp mình có trăm page, trăm component khi load lần đầu bắt người dùng tải toàn bộ về thì hơi phí mất time hơn 🤪. Điểm thuận lợi thì cũng có là nó tải toàn về nên chuyển route nó nhanh vãi vì nó tải toàn bộ về lần đầu rồi.
Ở đây mình sẽ dùng kỹ thuật lazy load dùng đến đâu tải đến đó nhưng chuyển route thì hơi chậm 1 tí xíu nhưng chắc mình cũng không nhận ra lắm :)), do nó cần down js từ server về nữa. Dùng lazy thì cần 1 component <Suspense> để bao bọc nó nữa nhé, nó 1 fallbackUI, ví khi vào trang chưa load xong thì show tạm ra gì đấy chẳng hạn, không truyền cũng không sao, ra màn hình trắng thoi 😇
Ví dụ khi mình dùng lazy load cho page Login thì khi vào trang login nó mới tải js trang này về chứ ban đầu nó không tải toàn bộ nữa. Và khi mình build lại thì không còn 1 file js nữa mà sẽ ra nhiều file js khác kích thước cũng giảm hơn so với ban đầu mình không dùng :v
Khi mình dùng lazy load thì mình cũng cải thiện được cái Lighthouse nữa nha, công cụ của chrome để test performance.
Không phải lúc nào cũng ra 1 kết quả nên mình tính tương đối sai số mỗi lúc chạy nhé ae, 1 phần do mạng mẽo đồ nữa nghen. Ở đây có những chỉ số của trang web mình ae có thể dựa vào đây để test và cải thiện những chỉ số theo hướng dẫn của nó nhé
Hy vọng bài viết này giúp ae cải thiện được chút performance project của mình nhé. Thank you for watchinggggg 😜
Say hi những ngừi ae của toiiiii. Bài viết này là khai bút con Mạc Bục đã mua cách đây 2 tuần của toiiii kaka. Máy chạy nhanh quá làm mình cũng quên luôn viết bài trên blog của mình hehe.
À blog được tài trợ bởi server của ngừi anh thân thương [Thành Trung](https://thanhtrungit.net/). Ai mua VPS hay hosting thì có thể ghé [Dnclound.vn](https://dncloud.vn/) bao rẻ-khoẻ luôn nha ahihi. Thôi văn vở quá rồi kéo xuống thoiiiii 😂
Api này rất là hữu ích trong việc ae tạo modal, popup đó là `Create Portal`. Giúp mình tạo ra những component nằm trong bất kỳ vị trí nào trên page của chúng ta. Vậy tại vì sao nên sử dụng nó hè
🤙 React app của chúng ta được render trong element có id root chẳng hạn, thì ở đây sẽ render cả cái app chúng ra luôn. Trong 1 số trường hợp chúng ta muốn sử dụng Modal của mình nằm ngoài component nào đấy hoặc nằm ngoài id root luôn thì chúng ta sử dụng react portal nhé
🤙 Giả sử mình có 1 sidebar bên trái, content bên phải và trong content có 1 modal confirm nhé
Trường hợp xảy ra là z-index của sidebar: 20, z-index của content:10
Bây giờ cho dù z-index của modal confirm của mình tăng lên bao nhiêu đi nữa thì cũng không có tác dụng đâu vì thằng cha của nó là content nhỏ hơn moà. Trong những trường hợp này mình có thể đưa thằng modal ra ngoài cùng cấp với sidebar hoặc tốt hơn ra ngoài root luôn
Cách dụng thì ae sẽ import createPortal vào nhé, `có 2 tham số đầu tiên là jxs, tham số thứ 2 là element` chúng ta muốn chèn vào. Ví dụ muốn chèn vào body thì đơn giản chỉ cần document.body là okie rồi nè. Trong trường hợp ae muốn chèn vào element nào thì get element nó ra và dùng thoi
```
const root = document.getElementById('root') as HTMLElement
export default function Confirm({ visible, ok, cancel }: ConfirmProps) {
const handleOk = () => {
ok()
}
const handleCancel = () => {
cancel()
}
return createPortal(
Are you sure?
,
root
)
}
```
Nợ demo không bảo giờ trả nha ae 🤪. Có thì thắc mắc thì cứ ping mình giải thích nhé hihi. Chúc ae new day zui zẻ nhé 🤪
Hi 500 ae. Bài này mình giới thiệu về 1 hook là `useCallback` cũng như sử dụng nó ra sao nhé. Lướt thuiiiii
Chúng ta thường dùng `useCallback` khi mình không muốn function của chúng ta được khởi tạo lại mỗi lần component chúng ta re-render
```
const memoizedCallback = useCallback(() => {
doSomething(a, b)
}, [a, b])
```
Cách dùng thì tham số đầu tiên là 1 callback thực hiện việc gì đấy tham số thứ 2 là dependence. Mỗi lần dependence thay đổi thì function được chạy lại. Đơn giản vậy thuii
Mình có để demo phía dưới thì mình có 1 function handleClickTitle nó nhận vào value. Function là 1 object nên khi component re-render thì handleClickTitle sẽ tạo tham chiếu mới nên sẽ làm component re-render lại thôi. Trường hợp này mình dùng useCallback như demo dưới bạn có thể vọc để chạy nhé 😅
Say hi 5 chăm ae, bài này sẽ là bài đầu tiên trong chuỗi React Hook nâng chình xíu nhé. Bỏ qua các hook basic như useState, useEffect, useContext…Hơi nhiều lời rồi, lướt thoiiiii
Chắc ae đã biết thì component sẽ re-render state hoặc props được cập nhật, compoent cha re-render khiến component con cũng re-render theo. Vậy để không muốn component con bị re-render mỗi khi component cha re-render thì chúng ta dùng `React.memo` nhé
### **React.memo()**
React.memo() là 1 HOC (Higher-order component), chứ không phải hook
React.memo() dùng cho functional component
Chỉ render lại component nếu props thay đổi, còn không thì render lại kết quả của props cũ => có sử dụng kỹ thuật Memozation
Sử dụng shallow comparison
```
import "./styles.css";
import Title from "./components/Title";
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount((prev) => prev + 1);
};
return (
Click to increase count
Count: {count}
);
}
```
Ae thấy component `<Title/>` chắc chắn sẽ bị re-render khi mình click button, component cha re-render kéo theo nó cũng bị re-render theo. Nếu như component `<Title/>` tính toán nhiều nặng thì về performent không tốt còn ít thì hông đáng là bao 😉. Thay vì mình export như bình thường mình sẽ export như bên dưới `React.memo(NameComponent)`.
```
import React from "react";
export default function Title() {
console.log("title");
return This is Title;
}
--------------Convert to ---------->
import React from "react";
function Title() {
console.log("title");
return This is Title;
}
export default React.memo(Title);
```
`React.memo` chỉ check props thôi nha. Nếu như state trong component Title thay đổi thì nó vẫn re-render bình thường nha. Ngoài tham số là tên component thì sẽ nhận 1 function nữa nhé. Function này có 2 tham số, khi function đó return true thì props trước và sau giống nhau -> không làm component re-render. Ngược lại khác nhau thì render lại thuiiii.
À ví dụ ae truyền 1props qua component con dạng không nguyên thủy như object đồ á thì nó vẫn khiến component con re-render bình thường nha. Vì mỗi cần component cha re-render thì nó sẽ thay đổi cái tham chiếu của object props mình truyền sang nên component con tưởng props thay đổi nó re-render lại.
```
interface TitleProps {
address: {
street: string;
};
}
function Title(props: TitleProps) {
console.log(props.address);
return This is Title;
}
function equal(prevProp: TitleProps, nextProps: TitleProps) {
return prevProp.address.street === nextProps.address.street;
}
export default React.memo(Title, equal);
```
Các bạn để ý thì mỗi lần App chúng re-render thì nó sẽ tạo 1 instance address mới làm cho component React memo không còn hoạt động như mong muốn nữa, làm mình phải sử dụng thêm equal function hơi rườm rà.
Thì để hạn chế address được khởi tại thì mình dùng useMemo. Nào mình dùng những state, props liên quan muốn control thì mình truyền vào dependence như là bên useEffect vậy khi nào nó có sự thay đổi thì sẽ làm cho address tạo 1 instance mới làm cho Title chúng ta re-render lại còn mặc định [] thì sẽ chạy lần đầu tiên hoiiiii
Những vấn đề liên quan đến meno thì nó sẽ dùng ram của máy tính, càng dùng nhiều thì càng tốn nhiều ram, bù lại có được performance tốt hơn nên là ae cân nhắc khi dùng nha. Không phải gì cũng meno hết, vậy thì tốn ram nặng, những điện thoại yếu yếu tràn ram đơ cái máy tội lắm luôn :v
```
const address = useMemo(() => {
return {
street: K29 Nguyễn Như Đãi, Đà Nẵng"
}
}, [])
```
Hy vọng sẽ giúp các bạn có thể được cải thiện được performance trong dự án nha, tránh được việc re-render các component không cần thiết nhé
Hello 5 chăm ae, lại là Tú Pê Vê đây 😁. Bài viết này mình sẽ giới thiệu với các bạn về custom là gì và dùng như thế nào nhé.
Custom hook là những hook riêng do chúng ta tạo, để chúng ta chia sẻ state, logic giữa các component với nhau.
Mình để ví dụ ở đây anh em có thể vào xem thử nhé
Nhớ lúc trước ngồi xóa mớ value của key rồi chuyển thành type cho đúng value vừa xóa, vài dòng thì…i’m fine chứ 50 dòng thì uể thiệt 🤦♂️
Làm sao để biến cái đống JSON kia thành Typescript interface nhỉ, chẳng lẽ ngồi thay từng cái 🤔
Mình chia sẻ cho các bạn 1 cách nhanh hơn đó chính là dùng tool ở trang này: https://transform.tools/json-to-typescript các bạn chỉ cần dán cấu trúc JSON vào và việc còn lại để em nó lo. Sau đó các bạn sửa lại tên cho phù hợp trong dự án là được 👌
Hy vọng bài viết ngắn ngắn này sẽ support các bạn dài dài sau này nhé 😜
Trong bài này cùng mình phân biệt web storage và cookie nhé. Gét gô
**Web Storage & Cookie**
Web storage có 2 loại đó là Local Storage và Session Storage
Web storage lưu trữ được nhiều dữ liệu và dễ dùng hơn Cookie. Nhưng không có nghĩa họ bỏ không dùng Cookie nhé. Mỗi thằng có những ưu nhược khác nhau tùy case mình linh động nghen
Cả 3 đều dùng chung mục đích lưu thông tin trên trình duyệt để tiện xử lý sau này
Khác biệt lớn nhất giữa Local Storage, Session Storage và Cookie là thời gian lưu lại trên trình duyệt
**Local Storage**
Là Web Storage
Lưu lại vĩnh viễn trên trình duyệt. Khi mình chủ động xóa thì nó mới mất thui
Dung lượng lưu trữ khoản 5Mb – 10Mb tùy trình duyệt
Các trang khác không thể truy cập đến Local Storage nếu như khác domain
```
// Thêm item
localStorage.setItem('name', 'John Doe')
// Đọc item
localStorage.getItem('name') // 'John Doe'
// Xóa item
localStorage.removeItem('name')
// Xóa hết local storage
localStorage.clear()
```
**Session Storage**
Là Web Storage giống như Local Storage
Lưu lại 1 phiên dùng web thôi, đóng tab là mất hết data
Dung lượng lưu trữ khoản 5Mb – 10Mb tùy trình duyệt
Các trang khác không thể truy cập đến Session Storage nếu như khác domain
```
// Thêm item
sessionStorage.setItem('name', 'John Doe')
// Đọc item
sessionStorage.getItem('name') // 'John Doe'
// Xóa item
sessionStorage.removeItem('name')
// Xóa hết Session Storage
sessionStorage.clear()
```
**Cookie**
Có trước 2 thằng Local Storage và Session Storage
Không phải là web storage
Thời gian lưu trữ data có giới hạn, khi hết hạn thì cookie tự động bị xóa.Hạn này mình có thể set cho nó
Dung lượng lưu trữ chỉ khoảng 4KB => Nên lưu những data đơn giản, càng ít càng tốt, lưu quá nhiều thì mỗi lần mình truyền đi truyền lại thì nó tăng băng thông không tốt nghen
Cookie sẽ tự động truyền từ server xuống client và truyền từ client lên server thông qua mỗi header request
Server có thể cấu hình để các sub domain ví dụ `sub1.domain.com` có thể set cookie cho `sub2.domain.com`. Lưu ý là phải cùng domain cha là domain.com nghen
Cookie thường được tạo trên server bằng PHP, Python, Java hoặc Node.Js để truyền xuống client thông qua header của mỗi request
```
setcookie(
string $name,
string $value = "",
int $expires_or_options = 0,
string $path = "",
string $domain = "",
bool $secure = false,
bool $httponly = false
): bool
```
Cookie cũng có thể được tạo thông qua Javascript bằng cách dùng `document.cookie`.
```
document.cookie = 'yummy_cookie=choco'
document.cookie = 'tasty_cookie=strawberry'
console.log(document.cookie)
// console.log(document.cookie) "yummy_cookie=choco; tasty_cookie=strawberry"
```
Mình lấy ra dùng thì cũng hơi bất tiện. Mình log document.cookie thì nó ra hết nên mình phải tách từng phần tử ra. Nên thường người ta sẽ dùng thư viện [js-cookie](https://www.npmjs.com/package/js-cookie) để thao tác trên Client dễ dàng hơn. Những Cookie mà tạo bằng javascript thì không có cờ `HttpOnly` nha
* **Server Session**
Đây là phiên trên server, không phải ở client
Server sẽ tự động quyết định khi nào kết thúc phiên để đưa ra quyết định với client
Dung lượng lưu trữ không giới hạn, tùy dung lượng server quyết định
Giả sử người dùng sử dụng browser để login thông qua method post. Khi login okie thì server sẽ tạo ra 1 session id và nó sẽ return sesstion id vào trong cookie cùng với đó nó lưu sesstion id và db.
Sesstion id khi giải mã thì có những thông tin username, createdate…Khi thằng browser thực hiện request gì đó và có đính kèm cái cookie có giá trị là sesstion id thì server sẽ check lại db có sesstion id chưa và còn hạn thì nó sẽ xác thực okie response result thui nè
Hy vọng bài viết này giúp các hiểu và phân biệt được web storage và cookie nha 🤞
Trong bài viết này mình sẽ ôn lại concept function hay dùng trong React nhé
I/ Đầu tiên hay dùng nhất là Callback function. Nó chỉ là function truyền vào function khác như là 1 tham số thôi nên họ gọi là Callback function
```
const nums = [1,2,3,4,5]
const callBack = (item, index) => {
console.log(`STT: ${index} là ${item}`)
}
nums.forEach(callBack)
```
Như mình demo ở trên thì biến callBack đóng vai trò như là 1 tham số trong hàm forEach và nó là 1 function nên nó được gọi là Callback function
II/ Thứ 2 sẽ ngày đầu tuần 😁. Zui thôi chớ thứ là là Currying function . Nó là 1 function return về 1 function
```
// Ví dụ 1
function findNumber(num) {
return function () {
return num
}
}
console.log(findNumber(10)())
// Ví dụ 2
const findNumber = (num) => {
return (func) => {
const result = []
for (let i = 0; i number % 2 === 0)
```
`findNumber` gọi là currying function vì nó return một function mới. Vậy nên chúng ta phải `()` 2 lần thì nó mới chạy hết code trong nó được.
Chúng ta gọi findNumber(10) thì nó mới chỉ return về 1 function chưa chạy code bên trong function đó. Mình phải chạy nó thêm 1 lần nữa thì nó mới chạy function trong.
Mà function bên trong là function điều kiện nên mình sẽ dùng (number => number % 2 === 0) sẽ trả về những kết là số chẵn.
Hoặc mình có thể gọi bằng cách sau
```
// TH1
const newFunc = findNumber(10)
const value2 = newFunc((value) => value )
// TH2
const newFunc = findNumber(10)
const value2 = newFunc((value) => value % 2 === 0)
console.log(value2)
```
newFunc sẽ return về 1 function rồi thì mình có thể sử dụng cái newFunc để xử lý tiếp hehe
Chúc bạn new day zui zẻ keke 😘
Nếu như phiên bản có Promise giải quyết được được phần nào callback hell, nhưng vẫn chưa max ping thì đến ES7 chúng ta có thể xử lý bất động bộ 1 cách dễ nhìn và dễ đọc hơn với async/await
**Á à:** Async/Await không thay thế promise nha mà nó kết hợp với promise để cho ra cú pháp dễ nhìn hơn. Vì thế để học async/await bạn phải nắm được promise trước đã nghenn
**Async function:** Luôn luôn return về 1 promise nha
```
async function handle() {
return 1;
}
handle().then((value) => {
console.log(value);
});
```
**Await:** Chỉ hoạt động bên trong async function, không thể await bên trong một function thường. Không phải cái gì cũng await, await chỉ nên dùng cho promise thôi nghenn
```
const getApi = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Hello");
}, 3000);
});
};
const handle = async () => {
const value = await getApi();
return value;
};
// Bình thường như này handle(); là okie rồi. Muốn lấy kết quả từ function async về thì .then() nữa nghenn
handle().then((value) => {
console.log(value);
});
```
**Xử lý lỗi với async/await**
```
const getApi = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject("Loi roi");
}, 3000);
});
};
const getUser = async () => {
try {
const value = await getApi();
console.log(value);
} catch (error) {
console.log(error);
return null;
}
};
getUser().then((value) => {
console.log(value);
});
```
**Gọi tuần tự với async/await**
```
const getBooks = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(["book1", "book2", "book3"]);
}, 3000);
});
};
const getUser = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(["user1", "user2", "user3"]);
}, 3000);
});
};
const getAPI = async () => {
const books = await getBooks();
const users = await getUser();
return { books, users };
};
getAPI().then((value) => {
console.log(value);
});
```
**Tối ưu performance với `Promise.all()**
Ở đoạn code trên thay vì gọi lấy getBooks() xong rồi đến getUser() thì ra có thể cho function này chạy "cùng lúc"
```
const getAPI = async () => {
const [books, users] = await Promise.all([getBooks(), getUser()]);
return { books, users };
};
getAPI().then((value) => {
console.log(value);
});
```
Lại là TúPêVê cùng sê ri React Query đây. Bài này giúp ae hiểu Mutation trong React Query là gì, dùng nó ra sao nhé. Lướt xuống thôi 😆
mutate là 1 async function nha ae, nó xử lý bất động bộ nhưng nó không return promise đâu nghen
Lại là TúPêVê đây 😜. Bài này mình cùng tìm hiểu một số khái niệm quan trọng cũng như cơ thế caching của React Query như thế nào nhé 💋
Một số khái niệm ae cần lưu ý nhé
**staleTime** (default 0 ms): Thời gian data được cho là đã cũ. Khi get data xong thì sau một thời gian mình quy định thì data nó sẽ tự cũ. Mặc định 0 là khi get xong là nó cũ ròi á
Ae có cài react dev tool thì chỗ `stale` là nó hiển thị data đã cũ (stale) và thêm cái là active nữa thôi (để cho mình biết đang gọi query key nào á kiểu vậy `subcribe`) mấy cái dưới cũng là cũ nhưng inactive á nghen
**cacheTime** (default 5*60*1000 ms = 5 phút) : Thời gian data sẽ bị xóa ra khỏi bộ nhớ đệm. Data có thể cũ (stale) nhưng nó chưa bị xóa ra khỏi bộ nhớ đệm vì mình set staleTime < cacheTime. Thường thì người ta sẽ set **staleTime < cacheTime** . Ví dụ lúc phân trang mình ở trang 1 mình call api có page = 1, trang 2 mình call api có page = 2 thì khi sang trang 1 và 2 lại thì nó thấy data 2 page này còn lưu ở bộ nhớ đệm nên sẽ gọi data lưu ở cached ra và fetch ngầm ở dưới nếu có data mới khác data cache thì nó tự update lại data cached cho mình luôn 😍
**inactive:** Là khi data đó không còn component nào subcribe cả
```
const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList })
// result là 1 object chứa 1 vài state rất quan trọng như status, fetchStatus...
```
**Những state về khoảnh khắc của data**
isLoading hoặc status === ‘loading’: Query chưa có data
isError hoặc status === ‘error’: Query xảy ra lỗi
isSuccess hoặc status === ‘success’: Query thành công và data đã có sẵn
**Những state về data**
error: Nếu isError === true hoặc hoặc status === ‘error’ thì error sẽ xuất hiện
data: Nếu isSuccess === true hoặc status === ‘success’ thì data sẽ xuất hiện
**Đặc biệt là fetchStatus**
isFetching hoặc fetchStatus === ‘fetching’: Đang fetching API
isPaused hoặc fetchStatus === ‘paused’: Query muốn fetch API nhưng bị tạm dừng vì 1 số lý do nào đó
fetchStatus === ‘idle’: Query không làm gì cả, chạy xong rồi đang rảnh =))
**Nói chung đọc tới đây ae cũng rối cmnr kaka. Tóm lại như này cho khỏe**
status cho thông tin data có hay không
fetchStatus cho thông tin về queryFn có đang chạy hay không
Ví dụ thực tế ri cho ae dễ hình dung nghen, không hình dung được thì ib hỏi mình 😁 kaka
Click trang 1 call api thì loading = true do chưa có call xong rồi thì loading = false, trang 2,3..n cũng vậy
Khi quay về trang 1 hoặc những trang trước đó lại thì loading sẽ là false luôn vì nó đã có data trước đó rồi, `nhưng nó vẫn call api ngầm ở dưới á nếu có thay đổi thì nó sẽ cập nhật lại data mới thoi` => (isFetching = true lúc call api, khi call xong thì tất nhiên isFetching về false rồi)
**Cơ chế caching data**
Một data mà đã stale (cũ) thì khi mà gọi lại query của data đó, nó sẽ fetch lại api. Nếu không stale thì không fetch lại api. Vì mặc định là staleTime là 0 ms call xong nó cũ rồi. Hoặc setiing staleTime lên 60 * 1000 để 1 phút sau nó mới cũ thì click lại trong 1 phút thì nó không call api
Một data mà đã bị xóa khỏi bộ nhớ (tức là quá thời gian cacheTime) thì khi gọi lại query của data đó, nó sẽ fetch lại api (Dĩ nhiên roài). Nếu còn chưa bị xóa khỏi bộ nhớ nhưng đã stale thì nó sẽ trả về data cached và detch api ngầm, sau khi fetch xong nó sẽ update lại data cached và trả về data mới cho bạn
**Ví dụ siêu dễ hiểu cho ae về vòng đời caching của React Query**
```
Mặc định mình dùng cacheTime là 5 phút và staleTime là 0 nha
function A() {
const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
}
function B() {
const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
}
function C() {
const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
}
```
`A` component được mount
Vì không có query nào với `['todos']` trước đó, nó sẽ fetch data
Khi fetch xong, data sẽ được cache dưới key là `['todos']`
hook đánh dấu data là `stale` (cũ) vì sau `0`s
Bây giờ thì `B` component được mount ở một nơi nào đó
Vì cache data `['todos']` đã có trước đó, data từ cache sẽ trả về ngay lập tức cho component `B`
Vì cache data `['todos']` được cho là đã `stale` nên nó sẽ fetch api tại component `B`
Không quan trọng function `fetchTodos` ở `A` và `B` có giống nhau hay không, việc fetch api tại `B` sẽ cập nhật tất cả các state query liên quan của `B` và `A` vì 2 component cùng key => cùng subcribe đến một data
Khi fetch thành công, cache data `['todos']` sẽ được cập nhật, cả 2 comonent `A` và `B` cũng được cập nhật data mới
Bây giờ thì `A` và `B` unmount, không còn sử dụng nữa, không còn subcribe đến cache data `['todos']` nữa nên data `['todos']` bị cho là `inactive`
Vì `inactive` nên `cacheTime` sẽ bắt đầu đếm ngược 5 phút
Trước khi `cacheTime` hết thì ông `C` comopnent được mount. cache data `['todos']` được trả về ngay lập tức cho `C` và `fetchTodos` sẽ chạy ngầm. Khi nó hoàn thành thì sẽ cập nhật lại cache với data mới.
Cuối cùng thì `C` unmount
Không còn ai subcribe đến cache data `['todos']` trong 5 phút tiếp theo nữa và cache data `['todos']` bị xóa hoàn toàn
Hello mấy ae bài viết là bài đầu tiên trong chuỗi [React Query](https://tanstack.com/query/latest/docs/react/overview) cùng TúPêVê nghen. Gét Gô thuiiii
TanStack Query là cái tên gọi mới hay có thể gọi React Query là thư viện giúp quản lý các state bất đồng bộ như data từ api
**Nó có ưu điểm gì**
Quản lý cache data và cập nhật cực kỳ đơn giản
Không dùng global state, reducer để quản lý, không khó hiểu như redux
Có khả năng tương thích và mở rộng với mọi use-case gặp trong thực tế
**Vậy nó dùng gì để gọi api**
Tanstack Query không đảm nhận việc gọi API, việc gọi API sẽ thực hiện thông qua các thư viện bạn dùng như axios, fetch API. Còn Tanstack Query chỉ đảm nhận việc quản lý data và trigger gọi api khi cần thiết thôi
Như cách thông thường mình dùng useEffect để call api thì sao hè. Mình vd đoạn code mẫu dưới nhé
```
const [students, setStudents] = useState([])
const [isLoading, setIsLoading] = useState(false)
useEffect(() => {
setIsLoading(true)
getStudents(page, limit)
.then((res) => {
setStudents(res.data)
})
.finally(() => {
setIsLoading(false)
})
}, [])
```
Với cách này khá dài dòng chúng ta phải set đi set lại state rất là mệt. Còn với react query thì tương đối gọn hơn với code demo mẫu ở dưới
```
const { data, isLoading} = useQuery({
queryKey: ['students', page],
queryFn: () => getStudents(page, LIMIT)
})
//page đặt trong queryKey kiểu như devdependency trong useEffect vậy khi page thay đổi nó sẽ trigger chạy lại hàm getStudents cho chúng ta data mới
```
Thấy gọn quá hè, có được data, isLoading mà không cần phải cái useEffect dài dòng nữa =))
**Query Key là gì** : Nó là 1 cái key định danh cho cái query của mình và React Query nó sẽ quản lý việc query caching dựa trên Query keys của mình. Nó có thể là 1 mảng hoặc 1 số hoặc cái gì cũng được miễn sao để người khác nhìn vào biết được query của mình có nhiệm vụ gì
**Query Functions:** Nó là 1 function return về promise, promise này có thể return về resolve hoặc error
Hello mí ae bài viết này mình sẽ share kỹ thuật phòng chống XSS nghen. Ví dụ ở những field mà server trả về cho mình về dạng HTML thì ae không thể render như kiểu JSX `product.description` được nó sẽ gặp tình trạng kiểu như bên dưới, đấy là cách mà JSX chống lại tấn công XSS.
Vậy làm sao để mình render được dạng HTML lên React component của mình. Cách đơn giản nhất là mình dùng `dangerouslySetInnerHTML` mình truyền cho nó 1 object như bên dưới là nó render được dạng HTML rồi hehe
Cách render này lỡ như HTML của mình có chứa javascript thì website của mình cũng hơi nguy hiểm, nó có thể bị tấn công XSS vì thế thằng React mới có đoạn `dangerouslySetInnerHTML` kiểu như thông báo nhắc nhở cho mình những đoạn code trong này hơi nguy hiểm á. Mình demo test thử đoạn code bên dưới nghen
Khi mình click thì nó vẫn chạy được js show alert lên bình thường. Ví dụ đoạn này được user submit lên thì web mình dễ bị tấn công, có thể lấy access token của mình…thì vấn đề này giải quyết bằng cách cài package [`dompurify`](https://www.npmjs.com/package/dompurify) nó sẽ loại bỏ những đoạn code js đi tránh gây nguy hiểm cho trang web của mình.
Và sau khi dùng mình có thể so sánh kết quả như bên dưới, ban đầu mình không dùng thư viện dompurify và sau là sử dụng
Hy vọng bài viết này sẽ giúp ae hạn chế bị tấn công XSS tối thiểu nhé 😂
Hello ae nay mình share tip giúp ae loại bỏ giá trị undefined của key nhé. Ví dụ mình test demo 1 Object có 2 key optional của mình kiểu như bên dưới, thì khi hover vào chắc chắn sẽ nhận 2 type là string và undefined rồi
Ở đây mình sẽ tạo 1 function giúp loại bỏ giá trị undefined như bên dưới
– Cú pháp `-?` sẽ loại bỏ undefined key optional của mình
– `NonNullable` là 1 util của Typescript giúp loại bỏ đi giá trị underfined của 1 type
Khi sử dụng thì mình sẽ thấy 2 giá trị undefined của 2 key sẽ biến mất rồi hehe. Hy vọng ae sẽ áp dụng được nhiều case loại bỏ giá trị undefined không mong muốn nhé
Hello anh em lâu ngày quá. Hôm nay là 29 tết rồi, vừa dọn nhà xong tiện thể khai bút sê ri wordpress cho rộn ràng xíu hehe 😂
Mình mặc định là ae đã biết cài đặt wordpress à nếu chưa thì lên [đây](https://wordpress.org/download/) để tải về rồi tạo database rồi vô file config.php connect là được nghen
Theme wp thì sẽ nằm trong wp-content/themes. Mặc định là sẽ có 3 thư mục tương ứng với 3 theme của wp tạo sẵn cho mình. Việc của mình là tạo theme của mình trong này hoặc ae nào có sẵn thì có thể vào admin up giao diện lên cũng được nha rồi vô giao diện chọn theme của mình nhé. Để lập trình theme wordpress thì đầu tiên ae phải nắm được cấu trúc thư mục theme trong wordpress là gì nhé
Ngoài 2 file tất yếu phải có để chạy được theme wordpress là `style.css` để khai báo thông tin của theme chúng ta như tên theme, tác giả, version php… như bên dưới và file `index.php` đại diện cho trang chủ của mình thì có những file với những mục đích như sau
**– File style.css**
```
/*
Theme Name: Blog của Phạm Văn Tú
Text Domain: phamvantu.com
Version: 1.0
Requires at least: 4.7
Requires PHP: 5.2.4
Description: Theme wordpress by Tú Phạm
Author: Phạm Văn Tú
Author URI: https://v0.phamvantu.com
Theme URI: https://v0.phamvantu.com
*/
```
screenshot.png: Ảnh đại diện của theme
functions.php: Dùng để viết các function dùng chung cho theme, đường nhiên là những file trong theme sẽ dùng được nha
index.php: Hiển thị thông tin của trang chuyên mục
category.php: Hiển thị thông tin của trang chuyên mục
single.php: Hiển thị thông tin của trang chi tiết bài viết
page.php: Hiển thị nội dung thông tin của trang
tag.php: Hiển thị thông tin của trang chứa thẻ tag
404.php: Hiển thị nội dung của trang không tồn tại
search.php: Hiển thị nội dung của trang kết quả tìm kiếm
header.php: Chứa header của website dùng chung `get_header()`
footer.php: Chứa footer của website dùng chung `get_footer()`
sidebar.php: Chứa sidebar của website dùng chung `get_sidebar()`
**Đôi lúc mình muốn tách những block riêng để dùng chung tùy nơi mong muốn thì sao**
Thường mình sẽ tạo 1 folder template-part thì tạo file trong này rồi có thể gọi ra chỗ mình cần bằng cách `get_template_part('ten-thu-muc/ten-file')`
Ví dụ trang mình có blog bên Huynh đệ bên sidebar thì thay vì mình copy sang trang chuyên mục, chi tiết bài viết thì mình có tạo 1 file box-huynh-de.php trong folder template-part để mình cần dùng thì block thì `get_template_part('template-part /box-huynh-de')` là okie rồi
Ngoài những file php dùng cho các trang thì mình cần nhưng file style, image, js cho trang mình nữa thì mình hay tạo 1 thư mục public ví dụ như dưới
public
— css: chứa những file style của mình
— images: chứa những file hình ảnh
— js: chứa những file js
— libs: chứa những thư viện mình down về như font, slider, animation…
**Những phần nói trên là những file cơ bản cần dùng cho 1 trang nhưng chưa đủ 🤦♂️** . Ae xem 1 chút phần dưới để custom những page mình cần nha
Ví dụ trang web mình có 2 trang liên hệ với giới thiệu nhưng 2 trang lại có 2 giao diện khác nhau thì sao hè vì mình chỉ có 1 file là page.php để hiển thị trang chớ mấy nên nó đang nhận file page.php là trang chính thì cách giải quyết là mình sẽ tạo với tên file là page-ten-slug.php
Ví dụ với trang liên hệ thì sẽ có file tương ứng `page-lien-he.php` và trang giới thiệu `page-gioi-thieu.php`
Nhưng ví dụ trang mình có 5 trang giao diện như liên hệ 5 trang giao diện như giới thiệu chẳng lẽ mình tạo 1 page rồi copy qua hà =)). Rứa thì hơi cồng kềnh nên mình sẽ tạo ra 1 template page rồi vào admin mình sẽ chọn trang đó thuộc template nào thôi. Mình sẽ tạo 1 folder là template-page trong này mình sẽ tạo ra những file giao diện mình mong muốn và khai báo tên template cho nó `Template Name: Template1`
Tương tự chọn giao diện cho page thì post hoặc post type nào đó mình có thể chọn giao diện tương ứng bằng cách thêm 1 dòng dưới nữa Template Post Type: name_post_type
```
Hello 5 chăm ae 🤣. Bài viết này mình viết ra để lâu lâu tạo dự án thì vào copy cho nhanh á mà hehe. Một phần có gì ae tham khảo cách setup 1 dự án React Typescript như thế nào nhé
1️⃣ Đầu tiên đương nhiên mình phải create react app rồi
`yarn create react-app name_project --template typescript`
2️⃣ Tiếp theo mình cài Prettier để format code và Eslint để quản lý tiêu chuẩn code cũng như giúp các member trong team thống nhất quy chuẩn lúc dev luôn. `yarn add -D prettier eslint-plugin-prettier eslint-config-prettier`. À đừng quên setup editor vscode của mình Default Formatter => Chọn Prettier và Format On Save => true để tiện lúc code nhé
3️⃣ Thêm scripts vào package.json để check và sửa lỗi của eslint và prettier
```
{
"lint": "eslint --ext js,jsx,ts,tsx src/",
"lint:fix": "eslint --fix --ext js,jsx,ts,tsx src/",
"prettier": "prettier --check \"src/ ** /(*.jsx|*.js|*.tsx|*ts|*.css|*.scss)\"",
"prettier:fix": "prettier --write \"src/ ** /(*.jsx|*.js|*.tsx|*ts|*.css|*.scss)\""
}
```
Lúc này bạn chỉ cần chạy
– `yarn lint` để kiểm tra lỗi eslint
– `yarn lint:fix` để fix lỗi liên quan eslint (đôi lúc có những lỗi ae phải tự fix bằng tay nha)
– `yarn prettier` để kiểm tra lỗi prettier format
– `yarn prettier:fix` để tự fix lỗi prettier format
4️⃣ Tạo file `.prettierrc` để chia sẻ setting prettier giữa các editor. Các bạn có thể tạo ở trang [prettier này](https://prettier.io/playground/) cũng được nhé
```
{
"arrowParens": "always",
"semi": false,
"trailingComma": "none",
"tabWidth": 2,
"endOfLine": "auto",
"useTabs": false,
"singleQuote": true,
"printWidth": 80,
"jsxSingleQuote": true
}
```
5️⃣ Tạo file `.eslintrc` để setting eslint
```
{
"extends": ["react-app", "prettier"],
"plugins": ["react", "prettier"],
"rules": {
"prettier/prettier": [
"warn",
{
"arrowParens": "always",
"semi": false,
"trailingComma": "none",
"tabWidth": 2,
"endOfLine": "auto",
"useTabs": false,
"singleQuote": true,
"printWidth": 80,
"jsxSingleQuote": true
}
]
}
}
```
6️⃣ Tạo file `.editorconfig` để chia sẻ một số setting giữa các editor với nhau cho đồng bộ
```
[*]
indent_style = space
indent_size = 2
```
7️⃣ À hiện tại Tailwindcss cũng khá trend và dự án hiện tại trên công ty mình cũng dùng nữa nên mình viết sẵn lệnh cài luôn đỡ mất công qua doc 😁
```
yarn add -D tailwindcss postcss autoprefixer
- Tiếp theo mình chạy npx tailwindcss init để tạo ra file tailwind config
và edit content trong file lại thành: ["./src/ ** /*.{js, jsx, ts,tsx}"]
có thể thêm hoặc xóa các option cho phù hợp dự án ae nhé
- Và đừng quên import tailwind vào file css của mình nhé
@tailwind base;
@tailwind components;
@tailwind utilities;
- Nếu ae muốn sort các class của tailwindcss cho dễ nhìn thì
yarn add -D prettier-plugin-tailwindcss
```
Đôi lúc ae đang code gì đó nghĩ là xong rồi và commit push lên chuẩn bị tạo Pr cho mọi người review thì chợt nhận ra thiếu gì đấy cmnr. Thay vì vô viết rồi commit lại thì đã có **git amend**
Sau khi ae thay đổi những gì đã thiếu rồi thì ae `git add .`để lưu lại những thay đổi. Sau đó dùng `git commit --amend` và nó sẽ hiện ra cửa sổ để mình sửa đổi message commit lúc nãy. Sau đó mình`push lên lại thôi nhưng phải -f` để đè lên commit cũ nhé, vì nó làm thay đổi mã hash commit đó rồi.
Hy vọng sẽ giúp được ae thêm thay đổi commit dễ dàng hơn thay vì commit lên hoài như lúc xưa mình nhé kaka
Đôi khi trong 1 feature có nhiều commit quá cũng không clearn lắm. Vd mình làm feature A thì code html có 1 commit, implement có 1 commit, update abc có 1 commit nữa không tiện quản lí sau này lắm, làm commit history không clean lắm
`git rebase -i HEAD~3` (Head là con trỏ, trỏ đến vị trí của nó, 3 là tính từ vị trí Head => Gộp 3 commit từ vị trí head)
Lúc này nó sẽ xuất hiện 1 file để bạn edit. Thứ tự 3 commit gần đây hơi ngược so với khi dùng git log. Và mình chỉ được gộp những commit phía sau vào commit phía trước (Gộp vô commit đầu tiên luôn cho dễ nhớ).
Sửa pick thành s (hoặc squash cũng được). Sau khi xong thì nó xuất hiện thêm 1 file nữa để mình edit commit message. Và bây giờ chỉ cần `git push -f` là oke vì mình đã xóa 2 commit trước đó nên phải -f đè lên nghen ae.
Hello ae lại là mình với những bài về git đây 😜. Trong bài viết này mình sẽ undo lại những thay đổi về trạng thái ban đầu ae cùng tham khảo nhé
### **Hoàn tác những file ở local changes về trạng thái ban đầu:**
`git checkout name_file_change.ext`
Hoặc `git restore name_file_change.ext`
Hoặc khi change Vscode bên thanh bar trái cũng có xuất hiện những file change mình muốn undo file nào thì chỉ cần chọn vào mũi tên back rồi Discard Changes nó là oke
### Undo những file ở khu vực stage changes, khu vực mà sau khi mình add. lên
git reset `name_file_change.ext`
Hoặc git restore -S `name_file_change.ext`
Hoặc khi add rồi bên thanh bar trái cũng có xuất hiện những file Staged Changes mình muốn quay lại thì chỉ cần chọn dấu – là oke
### Undo những file ở khu vực commited trong quá khứ
Lấy mã commit đó, có thể lấy bằng cách click source control bên thanh bar trái, phía dưới có mục file history list ra những commit ở file này. Hoặc git log –oneline
`git restore --source=mã_commit name_file_change.ext`
Hoặc có thể click chuột phải tại file history rồi chọn Restore(Checkout)
### Undo commit với git reset
git reset mã_commit => Đưa thay đổi về khu vực Changes
git reset –sort mã_commit => Đưa thay đổi về Staged Changes
git reset –hard mã_commit => Mất luôn thay đổi. Ít dùng do khá nguy hiểm vì nó xóa luôn commit sau nó cmnr =))
git reset –merger mã_commit => Giống –hard nhưng an toàn hơn, chỉ làm mất những thay đổi cần thiết. Còn những thứ mình đang code vẫn giữ nguyên
Có thể undo commit gần nhất bằng source controls trong Vscode
Hoặc nhanh hơn thì git log –oneline rồi muốn reset commit nào thì Ctrl+click mã hash đó rồi chọn Reset name_branch to commit rồi chọn option những bên trên
**Và sau khi reset muốn push lên phải git push -f nghen. Vì nó sẽ đè lên các commit của origin**
Branch nó giúp mình tạo ra những nhánh làm việc riêng biệt mà không ảnh hưởng lẫn nhau, dễ dàng quản lí code hơn.
### **Tạo 1 nhánh mới**
Nó sẽ tạo 1 nhánh mới dựa trên nhánh hiện tại `git branch new_branch_name`
Hoặc tạo 1 nhánh mới và chuyển sang nhánh mới luôn `git checkout -b new_branch_name` hoặc `git switch -c new_branch_name` (Cái mới ở git verson 2.23)
### List tất cả nhánh
Hiển thị tất cả nhánh trên local `git branch`
Hiển thị tất cả nhánh trên remote `git branch -r`
Hiển thị tất cả nhánh trên local & remote `git branch -a`
Đôi khi sẽ không hiển thị nhánh ở trên remote thì ae gõ `git fetch` trước để nó cập nhật lại repo của mình nghen
### Chuyển nhánh
Chuyển qua lại giữa 2 nhánh ở local `git checkout name_branch` hoặc `git switch name_branch`
### Đổi tên nhánh
Nếu tên nhánh hiện tại bị sai, sửa lại bằng cách `git branch -m new_branch_name`
Trường ở nhánh này muốn đổi tên nhánh khác `git branch -m old_branch_name` `new_branch_name`
Mình chỉ đổi được ở local thôi, nếu nhánh đó đã xuất hiện trên remote rồi thì khi mình push sẽ tạo ra nhánh mới trên repo
### Xóa nhánh
Xóa nhánh ở local `git branch -D local_branch_name`
Xóa nhánh ở remote `git branch origin --delete remote_branch_name` hoặc `git push origin :remote_branch_name`
### Push một branch
Để push branch từ local lên `git push origin local_branch_name` hoặc `git push origin -u local_branch_name` nhưng cách này thì lần sau chỉ cần `git push` thôi thay vì origin bla bla kia nữa (‘-u’ là viết tắt của ‘–set-upstream’. Nó cho git biết rằng hãy tự kết nối nhánh ‘local feature’ với ‘origin feature’
Câu lệnh giúp các ae không cần gõ chính xác tên local branch luôn `git push -u origin HEAD` (Head là nó tham chiếu đến đầu danh sách branch hiện tại)
Xem những local branch đã kết nối với remote branch thì `cat .git/config`
### Cập nhập branch đã xóa
Khi ai đó xóa một branch trên remote nhưng khi mình gõ `git branch -r` vẫn show ra origin branch đó bình thường, thì để đồng bộ thì `git fetch -p`
Trong bài viết này mình cùng tìm hiểu về file readme là gì nhé.
Nó là 1 file dùng để giới thiếu dự án, cấu trúc cũng tài liệu cho dự án. Tạo file README.md (tên này là tiêu chuẩn để cho github, gitlab.. nhận diện được đó là file mô tả cho dự chúng ta) do sử dụng cú pháp Markdown để viết nên file có đuôi là .md á nghen ae
Ae có thể lên trang [markdownguide](https://www.markdownguide.org/basic-syntax/) hoặc [document trên github](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax) của nó để xem cho đầy đủ cụ thể nhé. Mình có ví dụ những trường hợp thường dùng để viết mardown như các thẻ tiêu đề, thẻ văn bản, in đậm, in nghiêng, danh sách, chèn code….ae tạo file copy chạy thử nhé
```
# Đây là h1
## Đây là h2
### Đây là h3
Đây là một thẻ p bình thường
Đây là danh sách ul, li
- Đây là li 1
- Đây là li 2
[Đây là thẻ a](fb.com)

**In đậm**
*In nghiêng*
`console.log('Chèn code ngon lành luôn')`
```js
const a = 100;
```
```html
Hello Readme
```
```
git status
```
Đôi lúc ae không muốn git theo dõi file thay đổi của chúng ta chỉ cần tạo file `.gitignore`
Khi ae làm việc với nodejs thì sinh ra thư mục node_modules khá nặng, không cần thiết phải lên git làm gì vì khá tốn thời gian pull push code và cả tài nguyên lưu trữ git nữa
Để comment trên gitignore thì bắt đầu # vd: `# Comment```
Để ignore file thì chỉ cần ghi tên file là được `app.js`
Để ignore cả thư mục thì chỉ cần ghi tên thư mục là được `node_modules` nhưng nên thêm dấu / để phân biệt với file `node_modules/`
Để ignore tất cả các thứ bên trong thư mục folder: `folder/ ** `
Muốn thêm file a.txt trong node_modules được theo dõi trong git thì thêm !: `!node_modules/a.txt`
Để ignore tất cả các file có đuôi là `.exe` ở thư mục folder dù cho có nằm ở sub-folder đi chăng nữa: `folder/ **/** .exe`
Để ignore tất cả các file có đuôi là `.exe`: `*.exe`
Để ignore tất cả các file có tên bắt đầu là log: `log*`````
Trường hợp code trên remote repo có những thay đổi và cập nhật, anh em có thể cập nhật những thay đổi này trên local repo của bạn cho giống như trên remote repo bằng câu lệnh vd như `git pull orgin name_branch`
Đôi lúc trong team ai đó sửa code trên remote rồi nhưng mình cũng cập nhật code dưới local ở cùng 1 nơi. Thì lúc này git sẽ không cho phép mình push code lên mà mình phải pull code từ remote về xem chọn đoạn code trên remote hoặc dưới local hoặc cả hai hoặc kết hợi 2 cái lại…
Thường thì trước khi push code lên ae pull code mới nhất trên remote về git pull
Nếu có confict thì giải quyết nó nên chọn bỏ đoạn nào. Nếu đoạn code đó ae trong team code thì có thể thảo luận để okie hơn
Add file đó lại hoặc git add . cũng được
Commit những file change rồi push lên là done ròi :v
Hello ae có bài này chắc sẽ ngắn thôi nhưng có thể giúp ae control được nhiều tài khoản github trong cùng một máy dễ dàng hơn qua bài viết này nhé. Đi thoi…
Tại thư mục (~/.ssh/) nơi sinh ra id_rsa của các bạn ấy, mình tạo thêm 1 file config (Không có đuôi gì cả nha) để git nó biết được mình đang dùng tài khoản nào để thao tác pull push code.
Ae mở file config lên bằng vscode hoặc cái gì nào đó rồi mình sửa theo bên dưới nhé
```
#Default Github
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_kozocom
#Github personal
Host github-phamtu613.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_personal
```
Ở đây mình dùng 1 account ở công ty và 1 account cá nhân. À lúc tạo ssh key anh em có thể rename lại như mình cho tường minh nhé.
Mình lấy mặc định là tài khoản account cty do mình làm việc chủ yếu ở cty mà hehe. Tài khoản thứ 2 là tài khoản custom cá nhân của mình. Khi mình
Khi mình thực hiện những lệnh như clone, remote…thì ở tài khoản default đầu tiên thì mình vẫn giữ nguyên link git@github.com nhưng nếu mình thực hiện ở tài khoản thứ 2 thì thay vì `git@github.com` mình sẽ chuyển thành `git@github-phamtu613.com` nhé.
Câu lệnh `git log` dùng để xem các commit gần đây của mình như thế nào.
Mỗi commit sẽ có mã riêng biệt cho từng commit.
Thường nó sẽ dài khiến mình khó đọc thì lệnh `git log --oneline` hiển thị ngắn gọn dễ đọc hơn. Nó sẽ lấy 7 ký tự đầu tiên và tên của commit đó
Và những comnmit này có là do mình commit á nghen. Không phải commit nào được push mới hiển thị ở đây. Cứ commit là log sẽ ra hết :v
Để đẩy code từ local lên trên remote thì thường dùng lệnh `git push origin name_branch`
Ví dụ mình muốn đẩy code lên nhánh main: `git push origin main`
Đừng trên trước khi push code phải add để thêm file thay đổi vào Staging, và commit nó nữa nhé
Có thể ae thấy bạn bè hoặc đồng nghiệp chỉ cần git push thôi thay vì origin tên nhánh này nọ. Bởi vì nhánh mặc định của git thì nó tự hiểu có origin phía sau rồi nên không cần viết thêm gì nữa
– Khi push thì mình phải đảm bảo đã có 1 repo trên server (github) rồi
– Local repo của mình phải kết nối với remote repo đó
**Để kết nối với remote repo thường sẽ có 2 cách**
Clone remote repo về local, lúc này dưới local đã có local repo và được kết nối sẵn với remote repo
Dùng câu lệnh git remote để tạo mối liên kết giữa local repo và remote repo (cách này thường thì sẽ có code dưới local gòi nha ae)
**Clone thì thường sẽ có 2 cách**
Clone bằng SSH (nên dùng cái này vì tiện và bảo mật) nhưng hơi phức tạp lúc setting ban đầu (tạo key, add key)
Clone bằng HTTPS
Để tạo SSH key thì bạn có thể tham khảo ở [đây](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) hoặc xem hướng dẫn của mình dưới nhé
Đầu tiên ae bật terminal lên gõ dòng lệnh sau: ssh-keygen -t ed25519 -C “email_bạn_dùng_ở_account_github”
Nó sẽ thông báo tạo ra 1 public key và 1 pirvate key ở ổ `/C/User/...` thường là vậy. Nếu bạn muốn đổi đường dẫn này thì có thể copy đoạn `/C/User/.../id_rsa_tupham` hoặc bạn có thể để nguyên rồi enter cũng không sao
Rồi các bước sau như nhập password bạn cũng ko cần nhập cứ enter cho đến khi nó thông báo oke
Để xem public key nhanh chóng thì ở bước 3 có thông báo your public key… C/User/… thì mình copy bỏ lên trình duyệt luôn rồi sửa thành C:/User… là hiển thị rồi đỡ tìm hehe. Thấy khỏe hơn nhiều chưa ae.
Hoặc nhanh hơn thì tại terminal đang gõ nhập lệnh `cat` rồi copy đường dẫn đó vô luôn nha ae
Sau khi tạo thành công thì nó sẽ sinh ra cho bạn 2 file là private key và public key theo đường dẫn mà bạn nhập tên file. File chứa public key sẽ có đuôi .pub phía sau. Add public key lên github nhanh thông qua [đường dẫn này](https://github.com/settings/ssh/new)
Check xem kết nối github thành công chưa: ssh -T git@github.com
Hiện như này là add thành công gòi nhé ae. Nếu chưa được thì xem mình gắn ssh key vô github chính xác chưa nhé vì có thể ae copy thiếu gì đó hehe
### Git status
Cho mình biết đang ở nhánh nào (On branch…)
Trạng thái branch của mình so với trên server github như thế nào, có thể sai thì code đã được update trên server lúc mình đang code. Muốn chính xác thì phải git fetch để tải code mới nhất về
Trạng thái các file, file nào đang được git theo dõi không
### Quan trọng: Các khu vực làm việc với git theo thứ tự như sau
Khu vực làm việc: Là nơi mình đang code, `ở local`
Khu vực staging: Sau khi dùng `git add` thì file sẽ được đưa lên khu vực này, `vẫn ở local`
Khu vực commited: Khi khi dùng `git commit` thì file từ staging sẽ được đẩy lên khu vực này, `cũng vẫn ở local`
Khu vực remote hoặc gọi là origin: Sau khi dùng `git push` thì file từ staggin sẽ được đưa `lên server`
### Git add
Câu lệnh này sẽ thêm 1 hoặc nhiều file thay đổi vào khu vực **Staging**
Thêm 1 file: `git add name_file_1`
Thêm 2 file: `git add name_file_2`
Thêm tất cả file: `git add .`
### Git reset
Đôi khi mình lỡ add nó lên khu vực Staging rồi nhưng muốn back lại 1 hoặc nhiều file về khu vực code
Khôi phục 1 file từ Staging về khu vực code: `git reset name_file_1`
Khôi phục nhiều file: `git reset .`
### Git commit
Câu lệnh này sẽ thêm những file từ khu vực Staging lên khu vực commit kèm theo title
Vd: git `commit -m "implement feature notify talk"`
Hoặc có thể thêm mô tả bổ nghĩa cho title thì: `git commit -m "implement feature notify talk" -m "description more"`
Hy vọng các bạn có thể nắm, hiểu được 4 khu vực làm việc để những câu lệnh git mình gõ xuống thêm % tự tin hơn kkk
### Git init
Chạy git init để tạo 1 repository (nơi chứa source code) trên máy tính. Sau khi chạy xong nó sẽ sinh ra 1 mục .git (có thể bị ẩn tùy máy), và source code chúng ta phải nằm ngang cấp với mục .git nhé
**Có 2 loại repository**
1 là ở local, trên máy tính
2 là ở server ví dụ như github, gitlab
### git config
Để biết đứa nào đẩy code lên
**Có 2 loại config**
Local: Dành riêng cho dự án
Để xem config ở local: git config –local –list
Global: Cho toàn máy tính chúng ta luôn
Để xem config ở global: git config –global –list
Bây giờ config để biết đứa nào push code lên nè: git config –global user.name “TuPV”
Thêm config email nữa là oki: git config –global user.email “tutu@gmail.com”
Nói nhỏ: Với terminal sử dụng Git bash thì khi dùng tiếng Việt đôi lúc sẽ dễ bị lỗi. Nên chuyển Unikey sang tiếng Anh nhé. Ví dụ mình gõ chữ tú rồi mình xóa đi 1 ký tự thì đôi khi nó hiển thị còn chữ tu nhưng vẫn báo lỗi á nghen. Hẹn gặp lại ae vào những bài tiếp theo trọng tâm hấp dẫn nhé 🥳
Hello ae. Bài này sẽ là bài đầu tiên trong chuỗi sê ri git của mình nhé. Đảm bảo đủ dùng bao gọn, bao dễ hiểu. Vì lúc trước mình sợ git lắm kaka, vì sợ mất code này nọ vài lần nên dùng rén rén. Nên hy vọng bài hày sẽ giúp phần nào ae rén như mình lúc xưa có thể tự tin bun bút tẹc ga. Đi thôi 😁
Lúc trước đi học chưa biết git thì ae mỗi đứa code 1 phần rồi gửi file với nhau đôi khi ráp vào thiếu hoặc lặp code thì rất là bất tiện. Chứ có GIT như bây giờ thì quá tiện rồi, biết ai là người code dòng này, code lúc nào và đồng bộ source code với nhau luôn
Github là gì? Hiểu nôm na đó là 1 hệ thống chưa dự án, source code chúng ta. Dùng cá nhân thì oke free tẹc ga, còn nếu dùng team lớn thì trả phí nghen
Bây giờ mình cài [git](https://git-scm.com/) nha (là 1 hệ thống quản lý phiên bản, theo dõi source code chúng ta). Sau khi cài đặt xong thì mình click chuột phải là nó sẽ hiện dòng `git bash here` hoặc bạn bật cmd lên gõ `git --version` là nó hiển thị phiên bản bạn đang dùng, vậy là okie rồi
Bài sau mình sẽ nói về git config cũng như tạo 1 thư mục được quản lý bỏi git như thế nào nhé.
Hello 500 ae, hôm nay mình sẽ giới thiệu sơ qua NVM giúp ae quản lý version node dễ dàng hơn nhé. Gét gô 🧐
Trước kia chưa biết đến NVM mình hay download trên [này](https://nodejs.org/en/) nè rồi cài dùng. Nhưng đôi khi gặp trường hợp cài dự án khác thì cần bản node mới hơn, thì mình phải gỡ đi cài lại bản mới.
Đến khi quay lại dự án cũ thì bản mới không tương thích nên phải gỡ bản hiện tại và cài lại bản cũ. Từ đó mình tìm thấy NVM giải quyết switch qua lại các version 1 cách nhanh chóng hehe.
Mình dùng windown nên mình lên [đây](https://github.com/coreybutler/nvm-windows) cài đặt nó, ae dùng ubuntu hoặc mac thì có thể lên [đây](https://github.com/nvm-sh/nvm) nghen. Cài đặt xong bạn có thể check version nvm `nvm -v` hoặc version node `node -v`
Để kiểm tra máy bạn đang dùng node version nào cũng như danh sách version trong máy bạn có thì => `nvm list`
Để cài mới 1 phiên bản node thì `nvm install name-version` Vd: `nvm install 16.17.1`
Và để sử dụng version nào thì `nvm use name-version` Vd: `nvm use 16.17.1`
Hy vọng với vài dòng đơn giản này có thể giúp ae bớt khổ trong việc chuyển đổi qua lại giữa các version node hehe. Để rõ hơn các bạn có thể xem trên document mình có gắn link ở trên nhé. Bye 500 ae nghen 🤗
Bài viết này mình sẽ tóm gọn về Destructuring, Rest parameter, Spread Syntax trong Javascript nhé. Mình thấy thực sự cần thiết và dùng rất nhiều trong dự án. Hy vọng với vài tóm tắt bên dưới sẽ giúp ae đỡ nhầm lẫn hơn cũng như biết được tên gọi của nó nhé
### Destructuring với Object
```
const user = {
name: 'Tu Pham',
age: 24,
}
// Thay vì viết dài dòng như thế này
// const name = user.name
// const age = user.age
// Có thể dùng Destructuring làm code ngắn gọn hơn
const { name: userName, age} = user // có thể đổi tên khác bằng cách : newName
console.log(userName) // Tu Pham
console.log(age) // 24
```
### Destructuring với Array
```
const res = [1, 2, 3, 4]
const [a, b, c] = res
console.log(a, b, c) // 1 2 3
```
### Spread Syntax
```
const user = { name: 'Tu Pham', age: 24, }
const cloneUser = {...user}
console.log(cloneUser) // { name: 'Tu Pham', age: 24, }
Cái này có thể gọi là shallow copy (copy nông). Vì nó chỉ copy giá trị của thôi. So sánh bằng thì thực ra nó không bằng đâu nghen. Sẽ có bài nói về tham trị tham chiếu sau để rõ hơn nghen
```
### Rest parameter
```
const handle = (a, b, ...c) => {
return c
}
const value = handle(1, 2, 3, 4, 5, 6, 7, 8]
console.log(value) // [3, 4, 5, 6, 7, 8]
// Những tham số còn lại gộp thành 1 mảng
```
Bài này thì mình sẽ tìm hiểu 2 cái type phức tạp hơn 1 chút nhưng cũng simple thôi đó là Object và Array
```
const obj: {} = {}
const user: {
firstName: string;
lastName: string;
isStudent: boolean;
school: (string | number)[]; // mảng có thể có số hoặc chữ. Có bài viết riêng về union types nghen
score: number[];
} = {
firstName: "Pham",
lastName: "Van Tu",
isStudent: false,
school: ["Hoa Tho", "Dang Thai Mai", "Phan Thanh Tai", "Dai Hoc Su Pham"],
score: [8, 9, 10]
};
```
Tiếp nối bài giới thiệu Typescript thì hôm nay chúng ta đến với Primitives types nhé.
Type assignment: const variable: dataTypes = value
Đại loại là mình truyền giá trị cho 1 biên nào đó
const age:number = 23
const name:string = ‘Tu Pham’
const isStudent:boolean = false
```
// Js
export function total(a, b) {
return a + b
}
// Ts
export function total(a: number, b: number, c?: number) {
return a + b
}
// c?: parameter này không bắt buộc (optional)
```
Bình thường ở Js mình có thể không khai báo type cho tham số nên có thể truyền bất cứ type nào vào, ngược lại ts chặt chẽ hơn bắt buộc phải khai báo kiểu data truyền vào. Có thể khai báo tham số không bắt buộc bằng cách thêm dấu ? trước type của nó là mình có thể truyền hoặc không rồi nè hehe.
Hôm nay mình ae cùng tìm hiểu về Typescript nhé. Đây là bài đầu tiên cũng như mở hàng cho sê ri 🤪 Typescript sắp tới của mình. Hy vọng sẽ giúp cho ae hiểu cũng như nắm được phần nào đó thằng Ts hơi khó chịu này nhé hehe…..đi thôi 😉
**Định nghĩa** : Ngắn gọn nó là 1 ngôn ngữ lập trình, được phát triển bởi microsoft dựa trên javascript. Khi code thì nó sử dụng những compile như webpack để build ra và convert sang javascript lại, và nó sẽ có những type giúp code chặc chẽ, clean hơn, nó thường sử dụng phát triển cho những ứng dụng lớn. Bên cạnh đó thì code Ts dài, mất thời gian hơn, phải suy nghĩ nó là type gì đồi nữa :))
Bài sau mình cùng tìm hiểu về Primitives types trong Typescript nhé
Sau khi nghĩ dưỡng 2/9 hơn nữa tháng nằm qua 3 cái bệnh viện thì giờ mình quay lại đây. Hy vọng sắp tới sẽ chuyên cần hơn trong việc chém gió này keke.
Thôi vào việc luôn get go 😁
`margin-inline:` Nó sẽ tương ứng với việc các bạn viết margin-left và margin-right
Ví dụ luôn cho dễ đi vào lòng người nè: Bình thường mình muốn cho 1 block ra giữa mình có thể dùng `margin-left:auto` và `margin-right: auto` còn sau khi các bạn đọc đến đây rồi thì => `margin-inline: auto` thấy hịn hơn chưa 😁
`margin-block:` Tương tự nhưng khác chiều thôi nó sẽ tương ứng với top và bottom
Ví dụ luôn: Thay vì các bạn viết `margin-top: 20px` và `margin-right: 20px` => `margin-block: 20px` cũng hịn hịn hơn xíu gòi đó 😁
Thì có margin thì cũng sẽ có padding thôi chứ chạy đi đâu nữa 😝 => `padding-inline & padding-block`
`aspect-ratio:` là 1 thuộc tính giúp chúng ta hiển thị hình ảnh theo tỉ lệ (1:1, 16:9, 4:3).
```
.aspect {
aspect-ratio: 1/1;
// aspect-ratio: 16/9;
// aspect-ratio: 4/3;
}
.aspect img {
width: 100%;
height: 100%;
object-fix: cover;
}
```
Đa số trình duyệt đều hỗ trợ rồi tầm 80% trừ những trình duyệt cũ quá hoi (< safafi 14.8). Bạn có thể check trên trang caniuse.com nghen.
`inset` thuộc tính này thường giúp mình viết thay cho trường hợp top: 0, right: 0, bottom: 0, left: 0 để phủ 1 lớp absolute full thằng cha relative luôn hoặc top: 0, left: 0, width: 100%, height: 100% cũng có tác dụng tương tự thì mình có thể viết gọn thành `inset: 0` nó là viết tắt của `inset: top right bottom left` tương tự cách viết tắt của padding và margin thôi hehe
Hy vọng anh em đọc xong bài này có thể giúp anh em biết được vài thuộc tính mới trong css, áp dụng luôn vào dự án đang làm của mình cho quen tay nhé. Mình sẽ update bài này nếu có thêm cái mới nghen 🥰
### display
Để sử dụng flex trong css thì đơn giản chúng ta chỉ cần khai báo display: flex hoặc display: inline-flex
Về chức năng thì nó cũng như nhau, nhưng flex thì sẽ full 100% phần tử cha chứa nó còn inline-flex thì độ trộng phần tử bao nhiêu thì nó chiếm bấy nhiêu thôi
### flex-direction: row | row-reverse | column | column-reverse;
row: Giá trị mặc định sẽ là row theo chiều ngang trái sang phải
row-reverse: Các phần tử vẫn nằm theo chiều ngang nhưng hiển thị ngược lại từ phải qua trái
column: Các phần tử nằm theo chiều dọc từ trên xuống dưới
column-reverse: Các phần tử nằm theo chiều dọc được sắp xếp đảo ngược từ dưới lên trên
### align-items: stretch | flex-start | flex-end | center | baseline;
stretch: Giá trị mặc định sẽ là stretch làm cho các cột tự giãn ra cao bằng nhau
flex-start: Canh theo phần trên **đầu** thôi, còn nội dung ngắn dài tự thay đổi
flex-end: Canh theo phần trên **dưới** thôi, còn nội dung ngắn dài tự thay đổi
center: Canh giữa theo trục dọc của các phần tử
baseline: Nó sẽ canh theo nét chữ nằm theo 1 hàng ngang
### align-self: auto | flex-start | flex-end | center | baseline | stretch;
Nó cũng tương tự như align-item nhưng khác ở chỗ nó sẽ set riêng cho từng phần tử
### justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
flex-start: Giá trị mặc định các phần tử sẽ nằm phía bên trái
flex-end: Các phần tử sẽ nằm phía bên phải
center: Các phần tử sẽ nằm ở giữa
space-between: Nó sẽ tạo các khoảng trống giữa các phần tử bằng nhau
space-around: Nó sẽ tạo các khoảng trống giữa các phần tử bằng nhau và các phần tử cũng có khoảng trắng nữa ( = 1/2 khoảng trắng ở giữa)
space-evenly: Tạo ra các khoảng trống đều bằng nhau
Hello ae bài viết này mình sẽ sơ lược về thư viện React Hook Form API và những api mình hay dùng của thằng này nhé!
Link thư viện: [React Hook Form](https://react-hook-form.com/v6/api)
Mình thường sử dụng các hook chính để làm việc chủ yếu là hook useForm, Controller, ErrorMessage. Mình dùng bản v6 nhé
### Hook useForm
– Nó giúp mình tạo ra 1 Object form instance. Nó cung cấp đầy đủ tất cả các phương thức giúp mình lấy được giá trị, trạng thái. set value…Bạn có thể xem code demo của doc bên dưới
```
const { register } = useForm({
mode: 'onSubmit', // có thể là onBlur, onChange, onTouched
reValidateMode: 'onChange',
defaultValues: {}, // gán những giá trị mặc định khởi tạo của form mình
resolver: undefined, // Để mình truyền vào cho nó 1 cái validation resolver. Thường mình dùng yup nghen
context: undefined,
criteriaMode: "firstError",
shouldFocusError: true,
shouldUnregister: true,
})
```
– Đầu tiên cái useForm sẽ nhận vào 1 Object như trên
### Controller
– Nó giúp mình tự động bind những sự kiện vào ui control của mình
### ErrorMessage
– Mỗi lần cần show lỗi thì nó giúp mình show err ra.
Bài này nói sơ qua như vậy thôi nha. Tập tiếp theo ở đây nhé hehe
Khi ta có một function là test, khi function test thực thi, bằng cách console.log (ở dưới) đoạn text được in ra theo thứ tự,
nhưng khi ta setTimeout cho nó thì có sự thay đổi đoạn text sẽ in ra số 2 và 3 trước rồi sau đó mới in ra số 1
**Promise** sinh ra để xử lý các thao tác bất đồng bộ, trước khi có promise thì chúng ta thường xử dụng callback, mà callback thì dễ bị trường hợp callback hell (nó sẽ bị chọt sâu vào, rồi rắm, khó nhìn, khó hiểu)
**Promise** sinh ra ở phiên bản ES6 để giải quyết (khắc phục) các trường hợp thường mắc phải ở callback
Cách tạo ra một promise thì ta sẽ tạo một từ khoá new với promise trong constructor chúng ta sẽ có executor trong executor function chúng ta có 2 tham số (resolve và reject):
**Resolve** khi thao tác xử lý logic thành công (success)
**Reject** khi thao tác xử lý bị thất bại (failed)
và khi sử dụng Promise thì đối tượng promise được tạo ra, chúng ta sử dụng 3 hàm (phương thức) **then** / **catch** / **finally, then** và **catch** đều nhận những callback function, **then** nó được thực thi khi promise được resolve, **catch** nó được thực thi khi promise được reject, **finally** khi kết thúc thực thi promise của resolve và reject
Author: Lincoln (Linh Nguyen Van)
Bài viết này mình sẽ nói về routing trong React nghen. Nhưng mà ở version 5 thôi nhé, version mới mình chưa update hehe
Package: [react-router-dom](https://www.npmjs.com/package/react-router-dom)` **npm i --save react-router-dom@^5** `
### Các component trong react-router-dom
Router: Component bao bọc tất cả các component khác của routing, mình sử dụng là **BrowerRouter** còn các loại khác các bạn có thể tìm hiểu sau nhé. Và tất cả các component của reacr-router-dom đều phải nằm bên trong Router nhé
Route: Render component khi match với patch
Switch: Chỉ render **route đầu tiên** match path
Redirect: Redirect từ path này sang path khác
Link: Đi tới path tương ứng
NavLink: Giống như Link như có thêm activeClassName, thường làm cho menu để style cho item đang active
### **Sự khác biệt Route & Switch**
Route:Chỉ cần match với path thì render lên component đó lên
Switch: Nó sẽ chạy từ trên xuống dưới, check từng Route, cái nào match với path hiện tại thì render component đó và dừng tại đó luôn. Ngược lại không dùng Switch thì nó sẽ render tất cả component được match luôn
Switch bọc các Route lại
### **Route matching**
Mặc định exact = false, lúc đó Route sẽ match khi URL bắt đầu tới path
Khi exact = true, lúc đó Route sẽ match khi URL = path
### Redirect: Mình muốn chuyển từ path này sang path khách thì mình dùng Redirect nghen
Dùng bên trong Switch
Redirect từ path nào đến path nào. Có thể sử dụng thêm exact
```
// Chỉ cần bắt đầu /home thì sẽ tự động chuyển sang /
// Bắt buộc url là /home thì sẽ tự động chuyển sang /
// Cũng có thể chuyển mà vẫn giữ tham số url được luôn nha
```
Các hook trong react-router-dom
useHistory: Trả về **history** instance, dùng để navigate. Thường dùng để di chuyển qua trang khác thay vì dùng Link hoặc NavLink
useLocation: Trả về **location** object của URL hiện tại. Thường xử lý với URL params
useParrams: Trả về **path params** object của URL hiện tại. Khi muốn xử lý path params
useRouteMatch: Trả về **match** object của URL hiện tại. Khi làm nested routing
### Phân biệt Path params & URL params
**Path params**
Ví dụ: Route có path là: /todos/:todoId
User vào đường dẫn: todos/123 -> Path params là {todoId: ‘123’}
**URL params**
User vào đường dẫn: /todos?page=1&size=10
URL params là phần sau dấu chấm hỏi
Bài viết này mình sẽ tìm hiểu cách so sánh 2 mảng cơ bản trong javascript bằng kiểu dữ liệu Json nha.
JSON là viết tắt của cụm từ Javascript Object Notation thì đây 1 kiểu dữ liệu tuân theo 1 quy tắc nhất định. Mình thấy ngôn ngữ nào cũng sử dụng nó cả hehe.
Mình ví dụ sau này muốn lưu data nào đó vào database thì không ai mà lưu 1 mảng `const arr = [1, 2]` như thế này cả mà người ta sẽ chuyển đổi sang 1 kiểu dữ liệu Json xong rồi mới thêm vào database chứ hông là nó hông hiểu :d
### Cú pháp:
**JSON.stringify(value):** Chuyển giá trị sang dưới dạng JSON string
**JSON.`parse`(value):** Chuyển đổi giá trị JSON sang kiểu ban đầu của nó
Lúc trước mình cũng thắc mắc sao không dùng hàm toString để chuyển sang string rồi lưu luôn cho khỏe :v.
Nếu dùng `JSON.stringify` thì nó sẽ lưu dưới dạng Json string. Vậy mình muốn lấy ra lại giá trị ban đầu [1,2,3] thì mình dùng JSON.parse(value) nha
`JSON.parse([1,2,3]) -> [1,2,3]`
```
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
console.log(arr1 == arr2); // false
console.log(JSON.stringify(arr1) === JSON.stringify(arr2))// true
```
Nếu như so sánh bình thường thì sẽ ra kết quả là false, liên quan đến by Reference trong Js hiểu nôm na như có sẽ lưu địa chỉ của giá trị chứ không giá trị của nó nên nếu so sánh thì nó so sánh địa chỉ đó thôi hehe. Còn so sánh theo chuỗi Json String thì okie rồi nè hehe.
Nay mình cùng tìm hiểu các cách khác nhau để style trong React nghen.
### I. Inline styles
– Thêm vào thuộc tính style của tag html, và viết các thuộc tính theo dạng camelCase nha. Ví dụ backgroundColor, textAlign…
```
```
– Cách này ít dùng, chỉ dùng khi cần thay đổi styles theo props, hoặc giá trị động từ api trả về chẳng hạn
### II. Css
– Cách này tạo 1 file css bên ngoài và import vào dùng những class, id… đã định nghĩa sẵn bên file css này là okie rồi
```
/* styles.css */
.text-center {
text-align: center;
}
/* component.js */
import './styles.css';
```
### III. Scss & Bem
– Cũng như cách trên nhưng tạo file scss và có thể viết sass trông gắn gọn, sạch sẽ hơn ahihi
```
/* styles.scss */
.menu {
display: flex;
&-item {
position: relative;
}
&-link {
color: "blue";
}
}
/* component.js */
import './styles.scss';
```
### IV. Css Module
– Đối với cách này thì sẽ tạo ra 1 unique class bằng cách thêm các chuỗi vào tên class nên sẽ ko gặp vấn đề về trùng class giữa các dev với nhau
```
/* styles.module.css */
.title{
color: red;
}
/* component.js */
import './styles.module.css';
Title is here
```
### V. Styled Component
– Cách này viết css trong js luôn. Nó sẽ tự tạo ra class unique cho mình nên cũng sẽ không gặp vấn đề trùng class cách css module
```
/* component.js */
const TitleStyles= styled.h1`
text-align: center;
color: ${props => props.color || "red"}
```
Life cycles là 1 phần khá quan trong trong React, nó giúp mình hiểu hơn về cách hoạt động của 1 component ra sao. Bài viết này mình sẽ nói về life cycles trong React nghen.
Đầu tiên thì các component life cycle chỉ có trong Class Component thôi nha.
**Với component trong ReactJs, life cycle gồm 3 giai đoạn:**
Mounting – Được tạo ra
Updating – Qua nhiều cập nhật, thay đổi
Unmounting – Bị hủy bỏ
Hình mô tả life cycles trong ReactJs bạn có thể đoán từng giai đoạn có những hàm nào luôn hehe
### I. contructor()
– Thường sẽ dùng để khai báo property hoặc state của component
```
class App extends PureComponent{
constructor(props) {
super(props);
this.DEFAULT_COLOR = "Green";
this.state = {
postList: [],
}
}
}
```
### II. componentDidMount()
– Thường để tạo data cho component như get API, update state…
– Ví dụ như này cho dễ hiểu nè.
Contructor chạy đầu tiên định nghĩa sẵn state postList
Component sẽ render đầu tiên, lúc này chưa có data gì đâu nghen
ComponentDidMount sẽ call api gì đó xong sẽ setState data được trả về từ API cho postList mới
Khi setState thì component sẽ re-render lại 1 lần nữa thì sẽ có data mới từ api show ra nè
### III. componentWillUnmount()
– Chạy 1 lần sẽ được gọi khi component của mình được hủy bỏ đi, vd như không render nó nữa hoặc chuyển trang
– Thường sẽ gọi nó để clear timeout hoặc interval nếu có dùng
– Rest dữ liệu trên redux nếu cần thiết
### IV. componentDidUpdate()
– Thường ít dùng
– Chỉ dùng nếu muốn handle update component khi click nút back trên url có query params
– Cần thận setState trrong này vì có thể sẽ gây ra vòng lặp vô hạn á, vì setState thay đổi sẽ re-render và gọi componentDidUpdate rồi setState thay đổi xong re-render tiếp….hehe
Hy vọng bài viết bài sẽ giúp các bạn hiểu hơn về life cycle trong React nha
Có nhiều phương pháp chia component nên số loại component sẽ khác nhau. Ở bài viết này mình chia React theo 2 loại component
**– Container: Smart component**
Quản lý, xử lý xử liệu (Có thể get api lấy data, hoặc data tĩnh, cung cấp dữ liệu và có dữ liệu để render)
Không quan tâm render UI như thế nào
Chỉ quan tâm render cái gì
Có thể chứa container con và các components
**– Component: Dumb component**
Thằng cho cái gì render cái đó
Không cần biết dữ liệu đến từ đâu
Thường chỉ có props, không có state
Tái sử dụng, với props khác nhau thì sẽ render khác nhau
Mình ví dụ 1 block cơ bản dưới đây nha
### **Container**
**HomePage:** Thường tổng thể 1 trang là 1 container
Props: N/A
State: featuredPostList
Render:
Header
Banner
FeaturedPostList: state featuredPostList
### **Components**
Header: render header
Banner: render banner
FeaturedPostList
Props: featuredPostList
State: N/A
Render: a list of post
Hi mọi người hôm nay mình sẽ nói về 1 useContext() hook trong React nha.
Context cung cấp phương pháp để chia sẻ những giá trị giữ các component với nhau
Mình có cây component sau: App(status: false) -> Header -> Menu -> User -> Profile
Mình muốn truyền 1 dât từ App sang component Profile sẽ gặp vấn đề Props Drilling (truyền props thông qua nhiều component)
`Context` sẽ giúp mình truyền từ component cha xuống thằng component cháu, chắc luôn mà không cần thông qua các component trung gian nữa hehe
**3 bước đơn để tạo context**
```
import {createContext} from "react";
//B1. Tạo context
export const StatusContext = createContext();
// export để component con cháu sẽ có thể dùng được
// StatusContext trả về 1 Object có Provider và Consumer
//B2. Dùng provider cho component cha nhận được dữ liệu để component con có thể sử dụng được
// Thằng Provider sẽ bọc component cha
```
Với Provider sẽ có prop là value. Value nhận dữ liệu gì thì toàn bộ các childrent trong Provider đều có thể nhận được value đó
Ở component con `Component-Child`
```
import {useContext} from "react";
import {StatusContext} from "nơi export context";
// Để nhận được dữ liệu từ component cha thì có hook useContext() React viết sẵn để nhận data rồi hehe
const value = useContext(StatusContext);
// value sẽ là giá trị mà ở Provider component cha truyền vào
```
Và tới đây ở component con có data từ component cha truyền qua rồi thì thoải mái dùng thôi, không cần quan tâm từ component cha qua mình có bao nhiêu trung gian nữa hehe.
Tiếp nối bài viết về hook `useEffect()`thì hôm nay mình sẽ nói về hook `useState()` nha
useState() cũng là 1 hook cơ bản trong React, nó giúp mình sử dụng được state trong functional component
Nó cũng là 1 cái hàm thôi, đầu vào là 1 initialState có thể là giá trị hoặc cũng có thể là 1 function. Và đầu ra là 1 mảng có 2 phần tử tương ứng cho state và setState
**Cú pháp:** const [state, setState] = useState(initialState);
### Lưu ý khi dùng useState() chỗ này nghen
```
const [person, setPerson] = useState({ name: "Tu", address: "Da Nang" });
setPerson({ name: "Tu Pham" });
```
– Mình ví dụ có 1 state person và khi mình setPerson như trên thì giá trị sẽ chỉ còn lại là { name: “Tu Pham” } và nó sẽ replace giá trị trước đó
Nên trường hợp này mình nên clone nó ra rồi mới setState thuộc tính mình cần như hình dưới nghen
```
const [person, setPerson] = useState({ name: "Tu", address: "Da Nang" });
setPerson({ ...person, name: "Tu Pham" });
```
– Inital state chỉ chạy 1 lần đầu tiên các lần render sau coi như vô nghĩa nên nếu giá trị ban đầu inital state xử lý phức tạp thì có thể xử lý như cách dưới đây để chỉ chạy đúng 1 lần đầu thôi nghen :D.
```
const [person, setPerson] = useState(() => {
const initPerson = getPerson();
return initPerson
});
```
– Mình sẽ dùng inital state dạng callback function thay vì nó là 1 giá trị. Và useState() sẽ đảm bảo rằng giá trị khởi tạo trong này chỉ chạy đúng 1 lần mà thôi, những lần render sau không render nữa hehe.
– Những giá trị khởi tạo state như chuỗi hoặc số thì có thể ghi thẳng trực tiếp còn lại những xử lý tính toán phức tạp thì nên cho vào callback function để tối ưu hơn nha
Hi mọi người bài này mình sẽ nói về hook useEffect() nha
useEffect() là 1 hook trong React hook hỗ trợ cho functional component. Thường được dùng xử lý các vấn đề liên quan đến side-effects. Side effects có thể hiểu nôm na là những thứ mà nó tác động, chạy phía bên ngoài component của mình như
Gọi API lấy dữ liệu trên server
Tương tác với DOM
Subscriptions
SetTimeout, setInterVal
Chia làm 2 loại effects:
Effect không cần clean up: gọi API, tương tác DOM
Effect cần clean up: subscriptions, setTimeout, setInterVal
**useEffect()**
– Gồm 2 phần: side effect và clean up (option)
– Được chạy sau mỗi lần render
– Được thực thi ít nhất sau 1 lần render đầu tiên
– Những lần sau, chỉ được thực thi nếu có có dependencies thay đổi
– Effect cleanup sẽ được chạy trước khi run effect lần tiếp theo hoặc unmount
Cơ bản useEffect cũng là 1 cái hàm thôi nhận vào 2 tham số callback và dependencies: `useEffect(callback, dependency)`
– Mình ví dụ 1 code mẫu ở đây nha
```
// Được chạy sau mỗi lần render
useEffect(() => {
// Code side-effect ở đây...
return () => {
// Code clean up ở đây
// Sẽ chạy trước khi lần render tiếp theo hoặc unmount
}
}, [])
```
### Dùng với dependency thì mình sẽ ví dụ 3 trường hợp
### – Trường hợp 1: Không khai báo dependency
```
useEffect(() => {
// Luôn luôn chạy sau mỗi lần render
return () => {
// Code clean up ở đây
// Sẽ chạy trước khi lần render tiếp theo hoặc unmount
}
})
```
### – Trường hợp 2: dependency là empty
```
useEffect(() => {
// Chạy đúng 1 lần sau lần render đầu tiên
return () => {
// Code clean up ở đây
// Cũng chạy đúng 1 lần unmount
}
}, [])
```
### – Trường hợp 3: dependency có dữ liệu tham số đầu vào
```
useEffect(() => {
// Chạy sau lần render đầu tiên
// Nhưng lần sau có chạy hay không thì nó sẽ phụ thuộc vào dependency
return () => {
// Sẽ chạy trước khi lần render tiếp theo hoặc unmount
}
}, [dependency])
```
Chào các bạn! Hôm nay mình sẽ tìm hiểu về Module trong javascript là gì nhé.
Module có thể hiểu như nó là 1 bộ phận, 1 phần nào đó tập hợp rất là nhiều function, logic trong đó và khi chúng ta muốn sử dụng nó thì chỉ cần gọi nó ra mà thôi
**Tại sao chúng ta cần sử dụng nó**
Có tính bảo trì vì nó đóng thành 1 gói chia nhỏ nó ra rồi
Namespacing, vì trong javascript chúng ta khai báo 1 biến nào đó global thì tất cả mọi nơi đều sử dụng được thì nó xảy 1 cái vấn đề là giả sử function đó mình đặt cái tên trùng với 1 function ở đâu đó thì nó sẽ bị lỗi
Có thể tái sử dụng. Có thể đem các module đã viết kế thừa sang dùng những dự án khác
Xem ví dụ dưới đây sẽ giúp bạn hiểu hơn những gì nói nhé
– Nếu như mình export default thì mình sẽ import theo cách như trên là import name_function from “url file”
– Trường hợp mình muốn export nhiều thì mình dùng export name như ví dụ dưới đây
Trường hợp mình muốn đổi tên
Đổi tên đối với `expoort default` thì mình import tên gì cũng được không thành vấn đề
Đổi tên đối với `export name` ví dụ thay vì export myName thì sẽ thành myNameAs như này `export { myName as myNameAs }` và import thì phải là {myNameAs} thì sẽ là okie
Mình ví dụ 1 mảng đơn giản dưới đây và những cách mà lấy phần tử cuối trong mảng bạn có thể tham khảo áp dụng nhé
**const arr** = [‘a’, ‘b’, ‘c’, ‘d’];
**Cách 1:** Có thể dùng method pop để xóa phần tử cuối cùng trong mảng thu được phần tử cuối cùng. Hoặc theo cách dưới đây thì destructuring ra là sẽ được kết quả tương tự
`const last = [...arr].pop()`
**Cách 2:** Cách này có vẻ dễ hiểu hơn khi lấy độ dài của mảng -1 sẽ ra index phần tử cuối cùng
`const last = arr[arr.length - 1]`
**Cách 3:** Method reverse sẽ đảo ngược vị trí thứ tự các phần tử trong mảng và ta lấy phần tử đầu tiên là okie
`arr.reverse()[0]`
**Cách 4:** Method slice sẽ tạo ra 1 mảng mới sẽ 2 tham số (vị trí bắt đầu, vị trí kết thúc). Nếu chỉ truyền 1 tham số thì sẽ tạo ra mảng mới từ mảng cũ từ bắt đầu từ vị trí index truyền vào, vị trí end tự hiểu là đến hết mảng. Và truyền 1 tham số và số đó âm thì sẽ tính ngược lại từ phải sang trái.
`arr.slice(-1)[0]`
**Cách 5:** at là method mới của array, -1 nghĩa là lấy phần tử cuối cùng trong array. Nếu truyền vào 0 là lấy phần tử đầu tiên.
`arr.at(-1)`
Thử thách 6 ngày 6 đêm thành thạo các phím tắt trên Visual studio code để dev ảo diệu hơn…Get Gô ?.
▷==PHÍM TẮT CHỈNH SỬA VĂN BẢN==◁
1. Ctrl + Shift + K: Xóa dòng
2. Ctrl + Enter: Chèn dòng bên dưới
3. Ctrl + Shift + Enter: Chèn dòng trên
4. Ctrl + ⇓: cuộn xuống (đừng động đến chuột mà cuộn nội dung lên xuống bằng phím nhé)
5. Ctrl + ⇑: cuộn lên (đừng động đến chuột mà cuộn nội dung lên xuống bằng phím nhé)
6. Ctrl + Shift + Alt + ⇓: Thêm con trỏ chuột xuống dưới ngay con trỏ hiện tại
7. Ctrl + Shift + Alt + ⇑: Thêm con trỏ chuột lên trên ngay con trỏ hiện tại
mẹo: Giữ Alt + con trỏ chuột kích trái vào từng vị trí
8. Shift + Alt + ⇓: Copy nội dung dòng hiện tại xuống dưới
9. Shift + Alt + ⇑: Copy nội dung dòng hiện tại lên trên
10. Ctrl + D: Chọn văn bản giống văn bản bôi đen hiện tại
11. Ctrl + U: Hoàn tác thao tác phần tử chọn cuối cùng
12. Ctrl + Shift + L: Chọn tất cả đoạn văn bản giống hiện tại ( không phân biệt hoa thường )
13. Ctrl + ]: Đẩy dòng sang phải
14. Ctrl + [: Đẩy dòng sang trái
15. Home: Đi đến đầu dòng
16. End: Đi đến cuối dòng
17. Ctrl + end: Đi đến cuối file
18. Ctrl + home: Chuyển đến đầu file
19. Ctrl + F: Tìm kiến nội dung
20. Ctrl + H: Thay thế nội dung
21. F3: Tìm tiếp theo
▷==PHÍM TẮT KHÁC==◁
22. Ctrl + z: Quay lại thao tác nội dung trước đó
23. Ctrl + y: Lặp lại thao tác tiếp theo
24. Ctrl + [cách]: Gợi ý khi code các ngôn ngữ
25. Ctrl + w: Đóng tab hiện tại
26. Ctrl + [cộng,trừ]: To nhỏ font chữ khi code
▷==PHÍM HAY SỬ DỤNG==◁
1. Ctrl + [cách]: Gợi ý khi code các ngôn ngữ
2. Ctrl + /: Comment code
3. Ctrl + z: Quay lại thao tác nội dung trước đó
4. Ctrl + Y: Lặp lại thao tác tiếp theo
5. Shift + Alt + ⇓: Copy nội dung dòng hiện tại xuống dưới
6. Shift + Alt + ⇑: Copy nội dung dòng hiện tại lên trên
7. Ctrl + ]: Đẩy dòng sang phải
8. Ctrl + [: Đẩy dòng sang trái
9. Ctrl + D: Chọn văn bản giống văn bản bôi đen hiện tại
10. Ctrl + Shift + L: Chọn tất cả đoạn văn bản giống hiện tại ( không phân biệt hoa thường )
11. Ctrl + F: tìm kiến nội dung
12. Ctrl + w: Đóng tab hiện tại
13. Ctrl + [cộng,trừ]: To nhỏ font chữ khi code
Hy vọng bài viết này sẽ giúp các bạn thao tác trên vscode xịn hơn, cầm chuột ít hơn ? khi dev là good chóp rồi hehe
Hôm nay mình sẽ giới thiệu cho các bạn những cách căn giữa khối thường dùng nhất hiện nay, tùy trường hợp các bạn tham khảo áp dụng nhé.
Mình có đoạn html nhỏ mô tả vấn đề để căn giữa 1 phần tử khối bên trong như sau
Bây giờ để cho khối có class là box-wrapper căn giữa màn hình thì chỉ cần cho nó có thuộc tính `margin: 0 auto` thì nó sẽ tự chia độ rộng 2 bên còn trống ra đều nhau và thế là căn giữa rồi á :v
Bây giờ mình muốn khối có class box căn giữa khối bao quanh nó thì mình cũng có thể dùng `margin: 0 auto` tiếp luôn hehe, nhưng phải đảm bảo là width nó phải nhỏ hơn thằng cha chứa nó nha. Rồi vấn đề chính là mình muốn khối có class box-center canh giữa khối cha có class box thì sao… à thì cũng dùng `margin: 0 auto` luôn :))). Kết quả hiện tại nè
À khoan dừng lại khoảng chừng 2s :v, nãy giờ toàn `margin: 0 auto` á =)).
Để canh giữa nội dung ra giữa thì cho `text-align: center` ở khối có class box-center thôi là okie. Nếu trường hợp khối box-center kia là các tag inline hoặc là inline-block thì muốn cho ra giữa thì cho khối cha nó có class box thuộc tính `text-align: center` là được nha.
Bây giờ mình muốn canh giữa chiều ngang lẫn chiều chiều luôn thì mình sẽ dùng position nhé
Mình sẽ cho khối ngoài có class là box sẽ cố định bằng thuộc tính `position: relative` và khối con bên trong box-center chạy theo khối cha bằng thuộc tính position: absolute theo như đoạn code bên dưới nhé.
Mình sẽ set cho left: 50% có nghĩa là nó sẽ đẩy xuống 50% chiều cao của khối cha chứa nó và left: 50% thì nó sẽ tịnh tiến sang phải 50% so với chiều rộng của khối cha. Tiếp theo mình sẽ dịch ngược lên trên và sang trái 1 nữa chiều rộng và chiều cao của chính nó với thuộc tính transform như hình trên là xong rồi nè
Và cách còn lại này đơn giản hơn nữa khi chỉ cần style cho khối chứa ngoài nó là khối trong tự di chuyển theo cả chiều ngang lẫn dọc với flexbox, align-item và justify-content mặc định sẽ căn theo chiều dọc và chiều ngang của phần tử cha
– Cách cuối dùng này có lẽ sẽ ngắn gọn nhất luôn cho các ae đây hehe `display:grid; place-items: center`
Và đây là kết quả minh họa từ nãy giờ các bạn có thể test thực tế nha.
See the Pen [
Untitled](https://codepen.io/phm-vn-t/pen/KKyQxJL) by Phạm Văn Tú ([@phm-vn-t](https://codepen.io/phm-vn-t))
on [CodePen](https://codepen.io).
Vẫn còn 1 vài cách nữa nhưng mình nghĩ trên đây đủ để mình style hầu hết các trường hợp các bạn gặp rồi nè. Hy vọng sẽ giúp ích được cho các bạn nhé
Trong bài viết này mình sẽ hướng dẫn cho mọi người cách tùy biến scrollbar nhé. À nó chỉ có chạy ngon trên chrome, safari kể cả edge và coccoc luôn còn firefox thì không hỗ trợ nha.
Đầu tiên là thẻ chúng ta muốn dùng để áp dụng, như hình dưới mình set cho thẻ body nhé. Thứ hai là ta set cho độ rộng của thanh scrollbar là bao nhiêu, ở đây ta mình đang áp dụng cho body nên selector mình sẽ là `body::-webkit-scrol` nếu các bạn muốn áp dụng cho những thẻ khác thì chỉ cần thay thẻ body bằng thẻ tương ứng là được nhé.
Để set style cho thanh bar nền ở dưới thì mình dùng `body::-webkit-scrollbar-track`
Và cuối cùng để style cái mà chúng ta kéo lên xuống thì dùng `body::-webkit-scrollbar-thumb` là xong rồi nè.
Chúng ta có thể set thêm border-radius cho thanh scroll cũng như màu nền gradient cho bắt mắt trông xịn hơn hehe. Và đây là kết quả nè
See the Pen [
Untitled](https://codepen.io/phm-vn-t/pen/oNoppbY) by Phạm Văn Tú ([@phm-vn-t](https://codepen.io/phm-vn-t))
on [CodePen](https://codepen.io).
Hy vọng qua bài viết này sẽ giúp cho các bạn phần nào đó hiểu và áp dụng được cách style tùy biến scrollbar nhé.
Hôm nay mình sẽ giới thiệu cho các bạn thuộc tính clip path nhé. Nó sẽ giúp chúng ta trong việc cắt hình ảnh phức tạp. Ví dụ như hình ảnh dưới đây, thay vì mình dùng hình thì mình sẽ sử dụng clip-path nhé.
Các số trên hình mô tả tọa độ các điểm tương ứng. Nó sẽ hoạt động theo trục tọa độ và các điểm nối lại với nhau tạo ra hình mà mình cần, mình tưởng tượng trục x là chiều ngang, trục y là chiều dọc thì các bạn think xíu là ra ngay tọa độ trên thôi nè.
Thuộc tính này khó ở cách hiểu chút thôi, còn lại mình bê nguyên các tọa độ đó vào trong hàm polygon như hình dưới là xong rồi.
Bạn có thể test trên kết quả mình đã làm ví dụ dưới để hiểu hơn về cách hoạt động của clip-path nhé
See the Pen [
Untitled](https://codepen.io/phm-vn-t/pen/vYWREbe) by Phạm Văn Tú ([@phm-vn-t](https://codepen.io/phm-vn-t))
on [CodePen](https://codepen.io).
Đến đây mình nghĩ các bạn cũng hiểu được phần nào về cách hoạt động của clip-path rồi, sau này mình dùng những trang có sẵn như [clippy](https://bennettfeely.com/clippy/) thì ta hiểu cách hoạt động cũng như những thông số bên trong hàm polygon rồi thì mình dễ dàng tùy biến theo ý của mình gòi :v.
Hy vọng qua bài viết này sẽ giúp ae trong việc làm những hình phức tạp trong design dễ dàng hơn thay vì dùng hình trong design nha hehe
Hôm nay mình sẽ chia sẻ cho các bạn 1 chút về thuộc tính box-shadow nâng cao nha. Để dễ hình dung thì mình nhắc lại thuộc tính này tí nhé nó sẽ có 4 các giá trị như sau `box-shadow: x y scale blur color`. Tương ứng giá trị x sẽ là trục ngang, khi các bạn muốn tạo bóng về phía bên phải thì các bạn cho số dương, tương tự như giá trị y sẽ tạo bóng về phía dưới nếu cho giá trị dương ngược lại sẽ đổ bóng lên trên, scale mặc định sẽ bằng với khối chúng ta đang set luôn, blur là độ mờ của bóng, còn color thì không nói các bạn cũng hiểu là màu của bóng rồi hen.
Ví dụ mình có 1 hình như dưới đây, có thể các bạn sẽ nghĩ tạo các thẻ div rồi chia layout…để được như vậy, ở đây mình dùng box-shadow để các bạn hiểu sâu hơn về thuộc tính này nhé
Còn đây là đoạn code shadow để cho ra được như hình trên nè
Thực ra nhìn cái box-shadow dài thế thôi chứ tóm lại cũng chỉ là các giá trị quen thuộc cả, nhưng ở đây nó kết hợp lại thôi. Các bạn chỉ cần hiểu 1 cái box đầu tiên là sẽ hình dung ra liền hehe.
Mình muốn mỗi box sẽ cách nhau 10px nên box đầu tiên mình sẽ set cho nó `110px 0 0 0 yellow` sẽ dời sang trục x 1 khoảng 110px và có màu vàng các thuộc tính mờ hay scale mình để mặc định nhé
Box thứ 2 sẽ cách ra 220px có nghĩa là sẽ cách cục box chính cộng thêm box shadow mình vừa mới tạo và 20px cho 2 khoảng cách nữa đó hehe, hơi khó hiểu tí nhưng mà tí các bạn copy code chạy sửa lại thông số là hiểu ngay thôi
Đến đây chắc các bạn cũng đã nắm được cách dùng nhiều thuộc tính box-shadow chung với nhau cũng như cách nó hoạt động rồi hen, cop code ở dưới demo cho nó đỡ dài dòng =))
See the Pen [
box-shadow](https://codepen.io/phm-vn-t/pen/LYOJgVv) by Phạm Văn Tú ([@phm-vn-t](https://codepen.io/phm-vn-t))
on [CodePen](https://codepen.io).
Trong bài viết này mình sẽ giúp các bạn phân biệt 3 thuộc tính opacity: 0, display:none, visibility:hidden để dùng đúng cũng như đỡ gặp bug nhé 😀
Đầu tiên mình đi qua thuộc tính `opacity` trước nha. Nó sẽ chạy từ 0 đến 1, giá trị 1 là bình thường còn 0 là không thấy gì cả nhưng nó vẫn ở đó và chiếm diện tích và có thể nhấn vào được bình thường nha, bạn có thể thử hover vào thấy hình con trỏ chuột ngay
Tiếp theo `visibility:hidden` thì nó vẫn chiếm diện tích nhưng không thể nhấn vào được nên hover vào không có con trỏ gì nữa hết
Cuối cùng là `display:none` thì nó biến mất hoàn toàn khỏi trang luôn, không chiếm diện tích cũng như không thể nhấn vô được nữa
Thường 2 thuộc tính opacity và visibility sẽ đi chung với nhau để làm hiệu ứng với kết hợp với thuộc tính `transition` mượt hơn kiểu nhấn vào hiện ra như menu chẳng hạn. Còn display không hỗ trợ với transition nên đôi khi muốn hiển thị nhanh gọn thì có thể dùng `display:none` với `display: block` luôn
Hy vọng với sự so sánh ngắn gọn này sẽ giúp cho các bạn hiểu nên dùng thuộc tính nào để ẩn hiện với transition mượt mà hơn mà không phải hỏi vì sao lại Giật Giật nữa nhé hehe
Đôi khi các bạn muốn tạo nhiều phần tử giống nhau, có thể các bạn tạo 1 mảng rồi lặp hoặc là copy ra hoặc…thì `array.fill()` sẽ giúp bạn tiện hơn nhé
Mình muốn tạo 9 phần tử thì mình cho `Array(9)` các bạn muốn lặp bao nhiêu phẩn từ bên trong thì thay số tương ứng nhé. Hàm fill sẽ thay đổi giá trị tất cả các phần tử của một mảng thành một giá trị mình truyền vào, nếu không truyền gì thì mặc định các phần tử trong mảng là `undefined`nhé.
Và cuối cùng mình dùng map hoặc các hàm lặp tương ứng nhé để lặp các phần tử mình muốn lặp chẳng hạn như mình có có các component giống nhau chẳng hạn thì việc dùng như này sẽ giúp code của bạn clean hơn.
Hy vọng qua bài viết này sẽ giúp ích cho các bạn trong lúc làm việc thực tế nhé 😀