本文介紹如何在 React 項目中使用 CSS in JS 方案:emotion。
emotion#
emotion 是一種高性能且靈活的 CSS-in-JS 庫。它本身與框架無關,你可以在 vue 或者 react 中搭配使用。目前我們使用的是 react,已經有多個項目在生產環境穩定運行。emotion11 是對 emotion10 的略微改進,主要側重於開發者的體驗,TS 的類型改進,以及使用新版本的解析器:Stylis。
本文主要介紹在 React 和 TypeScript 中如何集成 emotion11。
變化#
包重命名#
emotion11 最重要的變化之一是大部分面向用戶的 package 都已經重命名。
重命名包的列表:
- @emotion/core → @emotion/react
- emotion → @emotion/css
- emotion-theming → moved into @emotion/react
- emotion-server → @emotion/server
- create-emotion → @emotion/css/create-instance
- create-emotion-server → @emotion/server/create-instance
- babel-plugin-emotion → @emotion/babel-plugin
- eslint-plugin-emotion → @emotion/eslint-plugin
jest-emotion → @emotion/jest
Hooks#
在內部使用鉤子以優化包的大小並在 React DevTools 中展示更好的 DOM 樹。
TypeScript#
TypeScript 類型已經被完全重寫。#
- 減少使用 emotion 時的構建時間,尤其是在大型項目中。
- 在許多情況下,不再需要為 emotion 組件手動指定通用參數
- 作為 props 的聯合類型得到了更好的支持,應該正確推斷
- 限制了 css 函數以防止傳遞無效的類型
- styled 的通用參數已更改,如果您指定 ComponentType,則需要刪除該通用參數
- styled 不再需要第二個參數 ExtraProps,代替地將其移動至 styled 調用之後。因此,styled<typeof MyComponent, ExtraProps>(MyComponent) 應該被改寫為 styled (MyComponent)({})
Theme 類型#
現在,為主題提供類型更加容易。您可以像這樣創建內置的 Theme 接口,而不是像以前那樣創建自定義實例:
css prop 類型#
基於使用的不同 JSX 運行時,emotion11 為 css prop 提供 TypeScript 支持的方式已經更改,可以僅對支持 className prop 的組件添加對應 css prop 的支持(因為 emotion 的 JSX 工廠函數採用提供的 css prop,對其解析並將生成的 className 傳遞給渲染的組件)。
Stylis V4#
emotion 使用的 css 解析器 Stylis 得到了升級,它修復了一些長期存在的解析邊緣情況,同時變得更小,更快。
Emotion 的緩存#
創建高速緩存的自定義實例時,現在需要 key 選項。請確保它是唯一的(並且不等於 “css”),因為它用於將樣式鏈接到緩存。如果多個緩存共享同一個鍵,它們可能會為彼此的樣式元素 “爭鬥”。 新的 prepend 選項可以使 Emotion 在指定 DOM 容器的開頭而不是結尾處添加樣式標籤。
使用#
安裝#
使用#
css prop#
emotion 提供主要的書寫 style 的方式是使用 css prop,它提供了一個簡潔靈活的 API 來對組件進行樣式設定。
有兩種方式使用 css prop:
Babel Preset#
Babel 預設可在使用 classic JSX 運行時自動啟用 Emotion 的 css prop。如果要使用新的 JSX 運行時,請不要使用此預設,而應使用 @emotion/babel-plugin
- 安裝
- 使用
.babelrc
如果您使用兼容的 React 版本(>=16.14.0),則可以通過以下配置選擇使用新的 JSX 運行時:
.babelrc
JSX Pragma#
在使用 CSS prop 的源文件頂部設置 jsx 編譯指示。此選項最適合測試 css prop 功能或在無法配置 babel 配置的項目(create-react-app,codesandbox 等)中。
與包含 linter 配置的註釋類似,此配置將 jsx babel 插件配置為使用 jsx 函數而不是 React.createElement。
如果您正在使用零配置工具來自動檢測應該使用哪個運行時(classic 還是 automatic),並且您已經在使用具有新 JSX 運行時的 React 版本(因此運行時為您自動配置了 runtime: 'automatic'),例如 Create React App 4,然後
編譯指示可能不起作用,您應該使用
。
使用 css prop#
主題#
Theme 包含在 @ emotion /react 包中。
將 ThemeProvider 添加到應用程序的頂層,並在樣式化組件中使用 props.theme 來訪問主題,或者提供一個接受該主題作為 css prop 的函數。
使用#
css function#
useTheme hook#
類型#
主題的類型需要在類型文件中聲明,否則 TS 類型會報錯。
types/emotion.d.ts
tsconfig.json
總結#
CSS in JS 的方案使用下來相比傳統的 less、sass 等優點的確不少,而 emotion 的類似方案也有很多,對我感受最深的一點是,打包速度提升很多,沒有冗餘的 CSS 出現,但是對於習慣了 css 寫法的人來說還是需要時間熟悉,總之,不妨一試。