1. 12:59 11/10/2026
## Tại sao cần một hệ thống theme thống nhất
Khi xây dựng ứng dụng React trên cả web và thiết bị di động, việc duy trì giao diện người dùng đồng bộ có thể là một thách thức. Mỗi nền tảng có những quy tắc riêng về kích thước phông chữ, khoảng cách và màu sắc, nhưng người dùng vẫn mong đợi trải nghiệm trực quan liền mạch. Sử dụng một hệ thống theme duy nhất giúp loại bỏ sự không đồng bộ này, giảm thiểu công sức bảo trì và đảm bảo thương hiệu được thể hiện nhất quán.
## Thiết kế các thiết kế token
Bước đầu tiên là xác định các thiết kế token cơ bản (design tokens) trong một tệp duy nhất. Thông thường, bạn sẽ cần:
- **Màu sắc**: màu primary, secondary, background, surface, text, error, v.v.
- **Phông chữ**: tên phông chữ, kích thước, chiều cao dòng, trọng lượng.
- **Khoảng cách**: khoảng cách, padding, margin, kích thước biên.
- **Các hiệu ứng**: độ bóng, độ mờ, độ cong góc.
Lưu trữ các token này dưới dạng một đối tượng JavaScript (hoặc JSON) mà cả hai ứng dụng web và ứng dụng di động đều có thể nhập. Việc tập trung hóa này giúp bạn chỉ cần thay đổi một giá trị duy nhất khi cần cập nhật giao diện.
## Tạo một theme provider
**Web (React):** Sử dụng `ThemeProvider` từ thư viện `styled-components` hoặc `emotion`. Áp dụng theme cho toàn bộ cây component thông qua context.
```js
import { ThemeProvider } from 'styled-components';
import theme from './designTokens';
function App() {
return (
<ThemeProvider theme={theme}>
<MyComponents />
</ThemeProvider>
);
}
```
**React Native:** Sử dụng `ThemeContext` từ `react-native-styled-components` hoặc một context tùy chỉnh đơn giản. Vì React Native không hỗ trợ CSS variables, bạn có thể ánh xạ các token vào các thuộc tính của `StyleSheet`.
```js
import React, { createContext, useContext } from 'react';
import { StyleSheet } from 'react-native';
import designTokens from './designTokens';
const ThemeContext = createContext(designTokens);
export const ThemeProvider = ({ children }) => {
const theme = { ...designTokens, styles: StyleSheet.create(designTokens.styles) };
return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;
};
```
## Sử dụng CSS variables (web) và ánh xạ (di động)
Trên web, bạn có thể khai báo các biến CSS trực tiếp từ các token:
```css
:root {
--color-primary: #007bff;
--font-size-base: 16px;
--spacing-md: 8px;
}
```
Sau đó, các component con có thể tham chiếu đến chúng bằng `var(--color-primary)`.
Trên thiết bị di động, sử dụng một helper tiện lợi để ánh xạ các token sang style objects:
```js
const useTheme = () => {
const theme = useContext(ThemeContext);
return {
colors: theme.colors,
spacing: theme.spacing,
// Ví dụ: lấy style từ theme.styles
getStyle: (key) => theme.styles[key],
};
};
```
## Hỗ trợ chế độ tối
Thêm một lớp token phụ (ví dụ: `colorsDark`) và chuyển đổi giữa các token cơ bản dựa trên trạng thái `colorScheme`. Sử dụng `useColorScheme` từ React Native và `useTheme` từ `styled-components` trên web để áp dụng lớp CSS động (`document.documentElement.setAttribute('data-theme', 'dark')`).
## Kiểm tra và bảo trì
- **Kiểm tra giao diện**: Viết các unit test kiểm tra xem các component có áp dụng đúng các token hay không.
- **Kiểm tra giao diện**: Sử dụng các công cụ như `react-native-testing-library` cùng với các snapshot trên web để phát hiện sự khác biệt giao diện.
- **Tự động hóa**: Thêm kịch bản kiểm tra giao diện vào quy trình CI/CD; bất kỳ sự khác biệt nào sẽ dừng quá trình triển khai.
## Mẹo thực tế
- **Bắt đầu từ sớm**: Định nghĩa các token ngay từ đầu để tránh việc sửa đổi giao diện một cách lộn xộn sau này.
- **Sử dụng các thư viện tiện ích**: Các thư viện như `polished` hoặc `styled-system` có thể giúp bạn tạo các biến một cách nhanh chóng.
- **Tài liệu hóa**: Duy trì một tệp README ngắn ghi lại ý nghĩa của từng token, các giá trị có thể sử dụng và hướng dẫn cách thêm một thiết kế token mới.
Bằng cách đồng bộ hóa giao diện thông qua một hệ thống theme duy nhất, bạn không chỉ tiết kiệm thời gian mà còn mang lại cho người dùng một trải nghiệm liền mạch, bất kể họ truy cập ứng dụng từ đâu.