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

Tamagui最佳实践技能,专注于React Native和Web跨平台UI开发框架Tamagui的高级应用模式。提供配置v4、编译器优化、样式化上下文、复合组件、设计令牌、主题化、性能优化和常见反模式解决方案。关键词:Tamagui, React Native, 跨平台开发, UI框架, 样式系统, 编译器优化, 设计系统, 移动开发, Web开发, 性能优化。

移动开发 0 次安装 10 次浏览 更新于 2/28/2026

名称: tamagui最佳实践 描述: 提供Tamagui v4配置、编译器优化、样式化上下文和跨平台样式的模式。在Tamagui项目(tamagui.config.ts, @tamagui导入)中必须使用。

此技能提供超越基础的Tamagui v1.x模式。它专注于配置v4、编译器优化、复合组件和常见错误。

强制上下文加载

处理这些组件时,在编写代码前请先阅读相应的模式文件:

组件类型 必读内容 交叉技能
对话框、表单、模态叠加层 @DIALOG_PATTERNS.md
表单、输入、标签、验证 @FORM_PATTERNS.md typescript最佳实践 (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支持推断的常量泛型。

使用createStyledContext的复合组件

对于像 <Button><Button.Text>点击</Button.Text></Button> 这样的复合API:

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" />

Dialog/Sheet的平台.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 - 设计令牌和主题化