Tamagui最佳实践指南 tamagui-best-practices

Tamagui跨平台UI框架高级开发指南,涵盖配置v4、编译器优化、样式化上下文、复合组件、主题系统、性能优化和常见反模式。适用于React Native和Web应用开发,提供TypeScript最佳实践、设计令牌管理和跨平台适配方案。

前端开发 0 次安装 0 次浏览 更新于 2/23/2026

名称: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 - 设计令牌和主题系统