Bài viết được sự cho phép của tác giả Lưu Bình An
Để hỗ trợ tính năng Theme, cho phép người dùng lựa chọn kiểu giao diện mà họ thích, trong React, bạn sẽ có thể tiếp cận 1 trong 2 cách dùng CSS-in-JS hoặc dùng CSS variable (tất nhiên không có hỗ trợ với IE)
Nếu dùng CSS-in-JS bạn sẽ có thể làm được nhiều thứ hơn, bạn có một bộ công cụ đủ các đạo cụ để mua mai trong JS. Bài viết này sẽ chỉ ra tại sao bạn nên dùng CSS variable cho nhu cầu làm theme
Tuyển dụng it react không yêu cầu kinh nghiệm
Nếu dùng CSS-in-JS, trong React bạn sẽ tổ chức một ThemeProvider
bằng React Context, dùng hook useTheme
để lấy giá trị trong ThemeProvider
, sẽ như thế này
import * as React from 'react'
import styled from '@emotion/styled'
import {ThemeProvider} from 'emotion-theming'
const themes = {
light: {
colors: {
primary: 'deeppink',
background: 'white',
},
},
dark: {
colors: {
primary: 'lightpink',
background: 'black',
},
},
}
const PrimaryText = styled.div(({theme}) => ({
padding: 20,
color: theme.colors.primary,
backgroundColor: theme.colors.background,
}))
function ThemeToggler({theme, onClick}) {
const nextTheme = theme === 'light' ? 'dark' : 'light'
return (
<button onClick={() => onClick(nextTheme)}>
Change to {nextTheme} mode
</button>
)
}
function App() {
const [theme, setTheme] = React.useState('light')
return (
<ThemeProvider theme={themes[theme]}>
<PrimaryText>This text is the primary color</PrimaryText>
<ThemeToggler
theme={theme}
onClick={(nextTheme) => setTheme(nextTheme)}
/>
</ThemeProvider>
)
}
export default App
Nếu dùng CSS variable, chúng ta khai bao một bộ các biến cần dùng, rồi chèn thêm data-theme
cho thẻ body
CSS
body[data-theme='light'] {
--colors-primary: deeppink;
--colors-background: white;
}
body[data-theme='dark'] {
--colors-primary: lightpink;
--colors-background: black;
}
Phần implement của React component lúc này sửa lại
import * as React from 'react'
import './css-vars.css'
import styled from '@emotion/styled'
const PrimaryText = styled.div({
padding: 20,
color: 'var(--colors-primary)',
backgroundColor: 'var(--colors-background)',
})
function ThemeToggler() {
const [theme, setTheme] = React.useState('light')
const nextTheme = theme === 'light' ? 'dark' : 'light'
React.useEffect(() => {
document.body.dataset.theme = theme
}, [theme])
return (
<button onClick={() => setTheme(nextTheme)}>
Change to {nextTheme} mode
</button>
)
}
function App() {
return (
<div>
<PrimaryText>This text is the primary color</PrimaryText>
<ThemeToggler />
</div>
)
}
export default App
Thẳng thắn mà nói, cả 2 cách làm này đều cho kết quả như nhau về mặt trãi nghiệm sử dụng, dùng CSS-in-JS sẽ có chút cảm giác hơi quá đà kỹ thuật, từ chuyên ngành là over-engineering.
Về hiệu năng thì sao?
ThemeProvider
CSS variable
Cũng không nhất thiết phải nhìn vào con số mili giây phải tốn cho việc render, vì simple này khá là bé. Bạn cứ hình dùng nếu một cây React Component với hàng trăm component con lồng ghép nhau, khi thay đổi giá trị trong ThemeProvider, tất cả những component đều bị render lại thì sẽ như thế nào? Việc dùng CSS variable sẽ mang lại hiệu quả hơn nhiều vì trình duyệt không phải làm quá nhiều thứ như cách 1.
Có một lý do mà mình cho là hơi ngụy biện khi khăng khăng đòi dùng JS-in-CSS theo mình đoán là các bạn thật sự chưa đủ tự tin cũng như “trình” để viết CSS hiện đại, bạn chuyên tâm nâng tầm JS của mình mà quên mất việc nâng tầm CSS, vón đã phát triển rất xa từ cái thời bạn dùng float
Use CSS Variables instead of React Context
Bài viết gốc được đăng tải tại vuilaptrinh.com
Có thể bạn quan tâm:
- React Context API và các Higher-order Components
- React hook là gì và lợi ích mà React hook đem lại
- Bỏ túi Cheatsheet React cho năm 2020 (kèm ví dụ thực tế)
Xem thêm tuyển dụng nhân viên it hấp dẫn trên TopDev