React Native 中 Styled Components 配置指南
什么是 Styled Components?
Styled Components 是一个 CSS-in-JS 库,让你可以在 JavaScript/TypeScript 代码中编写样式,并将样式与组件紧密结合。
核心特性
1. CSS-in-JS
// 传统方式
const styles = StyleSheet.create({container: { padding: 16 }
});// Styled Components 方式
const Container = styled.View`padding: 16px;
`;
2. 自动样式隔离
每个 styled component 都有唯一的 class 名,避免样式冲突:
const Button = styled.TouchableOpacity`...`;
// 生成类似:.Button-asdf1234 { ... }
3. 主题支持
内置主题系统,轻松实现深色/浅色主题:
const Title = styled.Text`color: ${props => props.theme.colors.text};
`;
4. 动态样式
基于 props 动态改变样式:
const Button = styled.TouchableOpacity<{ variant: 'primary' | 'secondary' }>`background-color: ${props =>props.variant === 'primary' ? '#007AFF' : '#5856D6'};
`;
优势对比
| 特性 | StyleSheet | Styled Components |
|---|---|---|
| 样式隔离 | ❌ 需要手动管理 | ✅ 自动隔离 |
| 主题支持 | ❌ 需要额外配置 | ✅ 内置支持 |
| 动态样式 | ⚠️ 条件语句复杂 | ✅ 简洁直观 |
| TypeScript | ✅ 支持 | ✅ 完整类型推断 |
| 样式复用 | ⚠️ 需要手动合并 | ✅ 继承机制 |
| 组件封装 | ❌ 样式和组件分离 | ✅ 样式与组件一体 |
如何配置 Styled Components
第一步:安装依赖
# 安装 styled-components
yarn add styled-components# 安装类型定义和 Babel 插件
yarn add -D @types/styled-components babel-plugin-styled-components
依赖说明:
styled-components: 核心库@types/styled-components: TypeScript 类型定义babel-plugin-styled-components: 优化开发体验和性能
第二步:配置 Babel
编辑 babel.config.js:
module.exports = {presets: ['module:@react-native/babel-preset'],plugins: [// ... 其他插件['babel-plugin-styled-components',{displayName: true, // 开发模式下显示组件名meaninglessFileNames: ["index", "styles"],pure: true, // 移除不必要的辅助代码},]],
};
配置说明:
displayName: true- 开发时在 React DevTools 中显示组件名称meaninglessFileNames- 忽略这些文件名,不生成 class 名pure: true- 启用 tree-shaking 优化
第三步:配置 TypeScript 类型
创建 app/types/styled-components-native.d.ts:
import 'styled-components/native';declare module 'styled-components/native' {// 主题模式类型type ThemeModeType = 'dark' | 'light';// 间距类型type SpacingType = {xs: number;sm: number;md: number;lg: number;xl: number;xxl: number;screenPadding: number;cardPadding: number;inputPadding: number;negSm: number;negMd: number;negLg: number;};// 字体类型type FontSizeType = {xs: number;sm: number;base: number;lg: number;xl: number;xxl: number;xxxl: number;};type FontWeightType = {regular: number;medium: number;semibold: number;bold: number;};type TypographyType = {fontSize: FontSizeType;fontWeight: FontWeightType;};// 颜色类型type ColorsType = {primary: string;secondary: string;background: string;text: string;textWhite: string;success: string;warning: string;error: string;info: string;border: string;overlay: string;transparent: string;};// 主题接口export interface DefaultTheme {mode: ThemeModeType;colors: ColorsType;spacing: SpacingType;typography: TypographyType;}
}
第四步:配置路径别名
更新 babel.config.js 和 tsconfig.json 中的别名配置:
babel.config.js:
module.exports = {plugins: [['module-resolver',{root: ['./app'],alias: {'@': './app','@providers': './app/providers',// ... 其他别名},},],],
};
tsconfig.json:
{"compilerOptions": {"baseUrl": "./","paths": {"@providers": ["app/providers"],"@providers/*": ["app/providers/*"]}}
}
第五步:创建主题系统
1. 主题结构
创建以下文件结构:
app/styles/theme/
├── custom/
│ ├── spacing.ts # 间距系统
│ └── typography.ts # 字体系统
├── dark/
│ └── index.ts # 深色主题颜色
├── light/
│ └── index.ts # 浅色主题颜色
└── index.tsx # 主题生成器
2. 定义间距系统
app/styles/theme/custom/spacing.ts:
export const spacing = {// 基础间距(4px 基准)xs: 4,sm: 8,md: 16,lg: 24,xl: 32,xxl: 48,// 特殊间距screenPadding: 16,cardPadding: 16,inputPadding: 12,// 负间距negSm: -8,negMd: -16,negLg: -24,
} as const;export type Spacing = typeof spacing;
3. 定义字体系统
app/styles/theme/custom/typography.ts:
export const typography = {fontSize: {xs: 12,sm: 14,base: 16,lg: 18,xl: 20,xxl: 24,xxxl: 32,},fontWeight: {regular: 400,medium: 500,semibold: 600,bold: 700,},
} as const;export type Typography = typeof typography;
4. 定义颜色
app/styles/theme/light/index.ts:
import { ColorsType } from "styled-components/native";const colors: ColorsType = {primary: '#007AFF',secondary: '#5856D6',background: '#FFFFFF',text: '#000000',textWhite: '#FFFFFF',success: '#34C759',warning: '#FF9500',error: '#FF3B30',info: '#5AC8FA',border: '#C6C6C8',overlay: 'rgba(0, 0, 0, 0.5)',transparent: 'transparent'
};export { colors };
app/styles/theme/dark/index.ts:
import { ColorsType } from "styled-components/native";const colors: ColorsType = {primary: '#0A84FF',secondary: '#5E5CE6',background: '#121212',text: '#FFFFFF',textWhite: '#FFFFFF',success: '#32D74B',warning: '#FF9F0A',error: '#FF453A',info: '#64D2FF',border: '#3A3A3C',overlay: 'rgba(0, 0, 0, 0.7)',transparent: 'transparent'
};export { colors };
5. 创建主题生成器
app/styles/theme/index.tsx:
import { DefaultTheme, ThemeModeType } from 'styled-components/native';
import { colors as darkColor } from './dark';
import { colors as lightColor } from './light';
import { spacing } from './custom/spacing';
import { typography } from './custom/typography';const getTheme: (type: ThemeModeType) => DefaultTheme = type => {const theme = type === 'dark' ? darkColor : lightColor;return {mode: type,spacing,typography,colors: theme,};
};export { getTheme };
第六步:创建 ThemeProvider
app/providers/ThemeProvider/index.tsx:
import { getTheme } from '@/styles';
import { createContext, PropsWithChildren, useCallback, useState } from 'react';
import { useColorScheme } from 'react-native';
import {DefaultTheme,ThemeModeType,ThemeProvider as StyledThemeProvider,
} from 'styled-components/native';// Context 类型定义
type ContextProps = {mode: ThemeModeType;theme: DefaultTheme;toggleTheme: () => void;
};// 默认主题
const defaultTheme: ContextProps = {mode: 'light',theme: getTheme('light'),toggleTheme: () => {},
};// 创建 Context
export const ThemeContext = createContext<ContextProps>(defaultTheme);// ThemeProvider 组件
export const ThemeProvider = ({ children }: PropsWithChildren) => {const isDarkMode = useColorScheme() === 'dark';const [mode, setMode] = useState<ThemeModeType>(isDarkMode ? 'dark' : 'light');// 切换主题函数const toggleTheme = useCallback(() => {setMode(prev => (prev === 'light' ? 'dark' : 'light'));}, []);const theme = getTheme(mode);return (<ThemeContext.Provider value={{ mode, theme, toggleTheme }}><StyledThemeProvider theme={theme}>{children}</StyledThemeProvider></ThemeContext.Provider>);
};
app/providers/index.ts:
export { ThemeContext, ThemeProvider } from './ThemeProvider';
第七步:导出样式系统
app/styles/index.ts:
// 主题 Design Tokens
export * from './theme';// 通用样式
export * from './common';
第八步:验证配置
创建一个测试组件 app/index.tsx:
import styled from 'styled-components/native';
import { ThemeProvider, ThemeContext } from '@providers';
import { useContext } from 'react';const Container = styled.View`padding: ${props => props.theme.spacing.md}px;background-color: ${props => props.theme.colors.background};
`;const Title = styled.Text`font-size: ${props => props.theme.typography.fontSize.xl}px;font-weight: ${props => props.theme.typography.fontWeight.bold};color: ${props => props.theme.colors.text};
`;const Button = styled.TouchableOpacity`background-color: ${props => props.theme.colors.primary};padding: ${props => props.theme.spacing.md}px;border-radius: 8px;margin-top: ${props => props.theme.spacing.md}px;
`;const ButtonText = styled.Text`color: ${props => props.theme.colors.textWhite};text-align: center;
`;function App() {return (<ThemeProvider><AppContent /></ThemeProvider>);
}function AppContent() {const { toggleTheme, mode } = useContext(ThemeContext);return (<Container><Title>Styled Components 配置成功!</Title><Title>当前主题: {mode}</Title><Button onPress={toggleTheme}><ButtonText>切换主题</ButtonText></Button></Container>);
}export default App;
第九步:重新构建
配置完成后,必须重新构建应用:
# 清理缓存并重启
yarn start --reset-cache# 或者重新构建
# iOS
yarn ios# Android
yarn android
配置检查清单
- ✅ 安装了
styled-components - ✅ 安装了
@types/styled-components - ✅ 安装了
babel-plugin-styled-components - ✅ 配置了
babel.config.js - ✅ 创建了类型定义文件
- ✅ 配置了路径别名(
@providers) - ✅ 创建了主题文件结构
- ✅ 定义了间距系统
- ✅ 定义了字体系统
- ✅ 定义了颜色(深色/浅色)
- ✅ 创建了主题生成器
- ✅ 创建了 ThemeProvider
- ✅ 导出了样式系统
- ✅ 重新构建了应用
常见配置问题
1. TypeScript 类型错误
问题:props.theme 报类型错误
解决:
- 确保
app/types/styled-components-native.d.ts文件存在 - 确保
DefaultTheme接口定义了所有需要的字段 - 重启 TypeScript 服务器(VSCode 中 Cmd+Shift+P -> "Restart TS Server")
2. 主题切换不生效
问题:点击切换主题,样式不变
检查:
- 组件是否在
ThemeProvider内部? - 是否使用了
props.theme.colors.xxx而不是硬编码颜色值? - 是否重新构建了应用?
3. Babel 配置不生效
解决:
- 清理缓存:
yarn start --reset-cache - 检查
babel.config.js语法 - 重启 Metro bundler
4. 找不到模块 '@providers'
解决:
- 检查
babel.config.js和tsconfig.json别名配置 - 确保路径正确:
'./app/providers' - 重启 TS 服务器
参考资源
- Styled Components 官方文档
- React Native 文档
- TypeScript 类型定义