名称:tamagui-最佳实践 description: 提供Tamagui v4配置、编译器优化、样式化上下文和跨平台样式化的模式。在Tamagui项目中必须使用(tamagui.config.ts,@tamagui导入)。
此技能提供超越基础的Tamagui v1.x模式。专注于配置v4、编译器优化、复合组件和常见错误。
强制上下文加载
处理这些组件时,在编写代码前先阅读相应的模式文件:
| 组件类型 | 必读内容 | 交叉技能 |
|---|---|---|
| 对话框、表单、模态覆盖层 | @DIALOG_PATTERNS.md | |
| 表单、输入框、标签、验证 | @FORM_PATTERNS.md | typescript-best-practices (zod) |
| 动画、过渡效果 | @ANIMATION_PATTERNS.md | |
| 弹出框、工具提示、选择器 | @OVERLAY_PATTERNS.md | |
| 编译器优化 | @COMPILER_PATTERNS.md | |
| 设计令牌、主题系统 | @DESIGN_SYSTEM.md |
配置v4快速开始
使用@tamagui/config/v4进行简化设置:
// tamagui.config.ts
import { defaultConfig } from '@tamagui/config/v4'
import { createTamagui } from 'tamagui'
export const config = createTamagui(defaultConfig)
type CustomConfig = typeof config
declare module 'tamagui' {
interface TamaguiCustomConfig extends CustomConfig {}
}
新项目推荐设置(将flexBasis对齐到React Native):
export const config = createTamagui({
...defaultConfig,
settings: {
...defaultConfig.settings,
styleCompat: 'react-native',
},
})
createThemes模式
对于自定义主题,使用带有调色板/强调色/子主题的createThemes:
import { createThemes, defaultComponentThemes } from '@tamagui/config/v4'
const generatedThemes = createThemes({
componentThemes: defaultComponentThemes,
base: {
palette: {
dark: ['#050505', '#151515', /* ...12种颜色 */ '#fff'],
light: ['#fff', '#f8f8f8', /* ...12种颜色 */ '#000'],
},
extra: {
light: { ...Colors.blue, shadowColor: 'rgba(0,0,0,0.04)' },
dark: { ...Colors.blueDark, shadowColor: 'rgba(0,0,0,0.2)' },
},
},
accent: {
palette: { dark: lightPalette, light: darkPalette }, // 反转
},
childrenThemes: {
blue: { palette: { dark: Object.values(Colors.blueDark), light: Object.values(Colors.blue) } },
red: { /* ... */ },
green: { /* ... */ },
},
})
令牌和主题语法
$前缀规则
- 属性:使用
$前缀引用令牌:<Text color="$color" fontSize="$4" /> - 主题键:在主题定义中不使用
$访问:{ color: palette[11] } - 变体中的令牌访问:使用
tokens.size[name]模式
变体展开运算符
特殊展开运算符将令牌类别映射到变体值:
const Button = styled(View, {
variants: {
size: {
// 映射尺寸令牌:$1, $2, $true等
'...size': (size, { tokens }) => ({
height: tokens.size[size] ?? size,
borderRadius: tokens.radius[size] ?? size,
gap: tokens.space[size]?.val * 0.2,
}),
},
textSize: {
// 映射字体大小令牌
'...fontSize': (name, { font }) => ({
fontSize: font?.size[name],
}),
},
} as const,
})
重要:在变体对象上使用as const,直到TypeScript支持推断的const泛型。
使用createStyledContext的复合组件
对于复合API如<Button><Button.Text>点击</Button.Text></Button>:
import {
SizeTokens,
View,
Text,
createStyledContext,
styled,
withStaticProperties,
} from '@tamagui/core'
// 1. 创建具有共享变体类型的上下文
export const ButtonContext = createStyledContext<{ size: SizeTokens }>({
size: '$medium',
})
// 2. 创建带上下文的框架
export const ButtonFrame = styled(View, {
name: 'Button',
context: ButtonContext,
variants: {
size: {
'...size': (name, { tokens }) => ({
height: tokens.size[name],
borderRadius: tokens.radius[name],
gap: tokens.space[name].val * 0.2,
}),
},
} as const,
defaultVariants: {
size: '$medium',
},
})
// 3. 创建具有相同上下文的文本(变体自动同步)
export const ButtonText = styled(Text, {
name: 'ButtonText',
context: ButtonContext,
variants: {
size: {
'...fontSize': (name, { font }) => ({
fontSize: font?.size[name],
}),
},
} as const,
})
// 4. 使用withStaticProperties组合
export const Button = withStaticProperties(ButtonFrame, {
Props: ButtonContext.Provider,
Text: ButtonText,
})
用法:
<Button size="$large">
<Button.Text>点击我</Button.Text>
</Button>
// 或从上方覆盖默认值:
<Button.Props size="$small">
<Button><Button.Text>小号</Button.Text></Button>
</Button.Props>
注意:context模式不适用于编译器扁平化。用于高级组件(按钮、卡片),而非原语(堆栈、文本)。
包装组件的styleable()
在功能组件中包装样式化组件时,使用.styleable()来保留变体继承:
const StyledText = styled(Text)
// 没有styleable - 变体继承被破坏
const BrokenWrapper = (props) => <StyledText {...props} />
// 有styleable - 正确
const CorrectWrapper = StyledText.styleable((props, ref) => (
<StyledText ref={ref} {...props} />
))
// 现在这可以工作:
const StyledCorrectWrapper = styled(CorrectWrapper, {
variants: {
bold: { true: { fontWeight: 'bold' } },
},
})
添加额外属性
传递泛型类型参数以添加额外属性:
type ExtraProps = { icon?: React.ReactNode }
const IconText = StyledText.styleable<ExtraProps>((props, ref) => {
const { icon, ...rest } = props
return (
<XStack>
{icon}
<StyledText ref={ref} {...rest} />
</XStack>
)
})
自定义组件的accept属性
在非标准属性上启用令牌/主题解析:
// 对于应接受主题颜色的SVG填充/描边
const StyledSVG = styled(SVG, {}, {
accept: { fill: 'color', stroke: 'color' } as const,
})
// 用法:<StyledSVG fill="$blue10" />
// 对于样式对象(如ScrollView的contentContainerStyle)
const MyScrollView = styled(ScrollView, {}, {
accept: { contentContainerStyle: 'style' } as const,
})
// 用法:<MyScrollView contentContainerStyle={{ padding: '$4' }} />
重要:在accept对象上使用as const。
属性顺序很重要
在styled()中,属性顺序决定覆盖优先级:
// backgroundColor可以被属性覆盖
const Overridable = (props) => (
<View backgroundColor="$red10" {...props} width={200} />
)
// width无法被覆盖(在展开后)
// 变体顺序也很重要:
<Component scale={3} huge /> // scale = 3(scale在前)
<Component huge scale={3} /> // scale = 2(huge覆盖)
反模式
动态样式破坏优化
// 错误 - 破坏编译器优化
<View style={{ width: someVariable * 2 }} />
<View backgroundColor={isDark ? '$gray1' : '$gray12'} />
// 正确 - 使用变体
const Box = styled(View, {
variants: {
dark: { true: { backgroundColor: '$gray1' }, false: { backgroundColor: '$gray12' } },
},
})
<Box dark={isDark} />
内联函数
// 错误 - 每次渲染都创建新函数
<View onPress={() => handlePress(id)} />
// 正确 - 稳定引用
const handlePressCallback = useCallback(() => handlePress(id), [id])
<View onPress={handlePressCallback} />
错误的导入路径
// 这些是不同的包,内容不同:
import { View } from 'tamagui' // 完整UI套件
import { View } from '@tamagui/core' // 仅核心(更小)
import { Button } from '@tamagui/button' // 单个组件
// 选择一种方法并保持一致
混合RN StyleSheet与Tamagui
// 错误 - StyleSheet值不解析令牌
const styles = StyleSheet.create({ box: { padding: 20 } })
<View style={styles.box} backgroundColor="$blue10" />
// 正确 - 全部使用Tamagui
<View padding="$4" backgroundColor="$blue10" />
对话框/表单的平台.OS分支
// 错误 - 手动平台分支
if (Platform.OS === 'web') {
return <Dialog>...</Dialog>
}
return <Sheet>...</Sheet>
// 正确 - 使用Adapt(参见@DIALOG_PATTERNS.md)
<Dialog>
<Dialog.Portal>...</Dialog.Portal>
<Adapt when="sm" platform="touch">
<Sheet><Adapt.Contents /></Sheet>
</Adapt>
</Dialog>
获取最新文档
要获取最新的API详情,直接获取markdown文档:
# 核心文档
curl -sL "https://tamagui.dev/docs/core/configuration.md"
curl -sL "https://tamagui.dev/docs/core/styled.md"
curl -sL "https://tamagui.dev/docs/core/variants.md"
curl -sL "https://tamagui.dev/docs/core/animations.md"
# 组件文档
curl -sL "https://tamagui.dev/ui/sheet.md"
curl -sL "https://tamagui.dev/ui/dialog.md"
curl -sL "https://tamagui.dev/ui/select.md"
# 完整文档索引
curl -sL "https://tamagui.dev/llms.txt"
对于HTML页面,使用web-fetch技能并选择适当的选择器。
快速参考
配置v4简写(Tailwind对齐)
| 简写 | 属性 |
|---|---|
bg |
backgroundColor |
p |
padding |
m |
margin |
w |
width |
h |
height |
br |
borderRadius |
媒体查询断点
| 令牌 | 默认值 | 服务器默认值 |
|---|---|---|
$xs |
660px | true |
$sm |
800px | false |
$md |
1020px | false |
$lg |
1280px | false |
$xl |
1420px | false |
动画驱动
| 驱动 | 平台 | 使用场景 |
|---|---|---|
css |
Web | 默认,最佳性能 |
react-native-reanimated |
Native | 原生动画必需 |
额外模式文件
- @DIALOG_PATTERNS.md - 对话框、表单、Adapt、可访问性
- @FORM_PATTERNS.md - 表单、输入框、标签、使用zod的验证
- @ANIMATION_PATTERNS.md - 动画驱动、enterStyle/exitStyle
- @OVERLAY_PATTERNS.md - 弹出框、工具提示、选择器
- @COMPILER_PATTERNS.md - 编译器优化详情
- @DESIGN_SYSTEM.md - 设计令牌和主题系统