mcpField
R
react-native-unistyles-v3

react-native-unistyles-v3

github.com/jpudysz设计与 UI3.0k560 次安装今天更新
代码仓库

关于 react-native-unistyles-v3

react-native-unistyles-v3 是面向 React Native 开发者的样式技能,介绍如何使用 Unistyles v3 构建主题化和响应式界面。它强调通过 C++ 核心和构建时处理实现样式更新而不触发重新渲染。

主要功能

  1. 01静态与主题响应式样式
  2. 02主题和断点配置
  3. 03基于属性的样式变体
  4. 04将主题值映射到组件属性
  5. 05Babel、Metro 与 Re.Pack 集成

适用场景

  1. 01为应用添加明暗主题
  2. 02按屏幕尺寸切换布局
  3. 03为组件实现尺寸变体
  4. 04将主题色传递给第三方组件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jpudysz/react-native-unistyles --skill react-native-unistyles-v3

安装后在 Claude Code 中输入/react-native-unistyles-v3确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api-reference.md
common-issues.md
setup-guide.md
styling-patterns.md
third-party-integration.md

详细介绍

React Native Unistyles v3 技能

你正在协助处理 React Native Unistyles v3 样式。v3 是一个零重新渲染样式库,拥有 C++ 核心(Nitro Modules)和一个在构建时处理 StyleSheets 的 Babel 插件(自 3.6.0 起,Metro 应用也可以改用实验性的零配置 Metro 集成)。它用一个响应式、支持主题且适配响应式布局的系统取代 React Native 的 StyleSheet。

前提条件

  • React Native 0.81+,且必须启用 新架构(从 RN 0.76 起默认启用,从 RN 0.82 起成为唯一架构)
  • React 19+(运行时强制要求)
  • react-native-nitro-modules(原生桥接依赖;请锁定精确版本 — Unistyles 3.4.0+ 需要 >= 0.37.1)
  • iOS 15.1+、Android 7+
  • 无需使用 react-native-edge-to-edge(从 v3.1.0 起为可选,现在已弃用)— 请改为在 android/gradle.properties 中设置 edgeToEdgeEnabled=true(Expo SDK 54+ 会自动启用)
  • Expo SDK 54+(如果使用 Expo;与 Expo Go 不兼容 — 需要开发客户端或预构建)
  • Xcode 16.4+(iOS,Nitro Modules 所需)

工作流

  1. 先阅读用户的代码 — 了解当前配置、导入和样式方案
  2. 识别意图 — 新建配置、添加主题、响应式设计、修复问题等
  3. 应用 v3 模式 — 使用本技能中的正确 API;需要详细信息时请查阅参考文件
  4. 验证正确性 — 检查是否违反关键规则(展开、桶文件重新导出等)

快速参考

StyleSheet.create — 3 种重载
import { StyleSheet } from 'react-native-unistyles'

// 1. Static object compatible with React Native StyleSheet.create
const styles = StyleSheet.create({
  container: { flex: 1, padding: 16 }
})

// 2. Theme function (reactive to theme changes, zero re-renders)
const styles = StyleSheet.create(theme => ({
  container: { backgroundColor: theme.colors.background }
}))

// 3. Theme + miniRuntime function (reactive to theme AND device state)
const styles = StyleSheet.create((theme, rt) => ({
  container: {
    backgroundColor: theme.colors.background,
    paddingTop: rt.insets.top,
    width: rt.screen.width > 768 ? 500 : rt.screen.width - 32
  }
}))
StyleSheet.configure — 一次性配置
StyleSheet.configure({
  themes: { light: lightTheme, dark: darkTheme },
  breakpoints: { xs: 0, sm: 576, md: 768, lg: 992, xl: 1200 },
  settings: {
    initialTheme: 'light',       // or: () => storage.getString('theme') ?? 'light'
    // adaptiveThemes: true,     // auto-switch light/dark based on OS (mutually exclusive with initialTheme)
    // CSSVars: true,            // web: themes as CSS variables (default: true)
    // nativeBreakpointsMode: 'pixels' | 'points'  // default 'pixels' = compare against rt.screen (pt/dp)
  }
})
变体
const styles = StyleSheet.create(theme => ({
  button: {
    variants: {
      size: {
        small: { padding: 4 },
        medium: { padding: 8 },
        large: { padding: 16 },
      },
      color: {
        primary: { backgroundColor: theme.colors.primary },
        secondary: { backgroundColor: theme.colors.secondary },
      }
    },
    compoundVariants: [
      { size: 'large', color: 'primary', styles: { borderWidth: 2 } }
    ],
  }
}))

// In component — call useVariants BEFORE accessing styles (always pass an object, `{}` for defaults)
styles.useVariants({ size: 'large', color: 'primary' })
return <View style={styles.button} />
withUnistyles — 将主题/运行时映射到非样式属性,或包装 Unistyles 无法绑定的视图

只接受 style 的 React Native / Reanimated 视图无需包装。对于 color/trackColor 之类的属性、contentContainerStyle,或不暴露原生 ref 的第三方视图,请使用 withUnistyles。

import { withUnistyles } from 'react-native-unistyles'
import { Button } from 'some-library'

const UniButton = withUnistyles(Button, (theme, rt) => ({
  color: theme.colors.primary,
  size: rt.screen.width > 400 ? 'large' : 'small'
}))

// Usage: <UniButton title="Press me" />
// Per-instance mapping: <UniButton uniProps={theme => ({ color: isOn ? theme.colors.on : theme.colors.off })} />

关键规则

  1. 绝不要展开样式——{...styles.x} 会破坏 C++ 代理绑定。始终使用数组语法:[styles.x, styles.y] 或 [styles.x, { marginTop: 10 }]

  2. 绝不要从 barrel 文件重新导出 StyleSheet——直接从 react-native-unistyles 导入。在 root 之外,Babel 插件只能识别通过该导入(或 autoProcessImports)调用的 StyleSheet.create,因此重新导出会导致检测悄然失效。(Metro 集成也能检测从你自己的模块重新导出的情况,但直接导入在任何地方都能正常工作。)

  3. 必须使用构建时集成——以下任选其一:

    • Babel 插件(默认):在 babel.config.js 中使用 ['react-native-unistyles/plugin', { root: 'src' }](必须设置 root;其下的每个文件都会被处理)
    • Metro 集成(3.6.0+,实验性,仅限 Metro):在 metro.config.js 中使用 react-native-unistyles/metro 提供的 withUnistylesConfig(config),不带选项,并移除 Babel 插件(两者同时使用会报错)。在 babel.config.js 的 plugins 中列有 babel-plugin-react-compiler 的纯 RN 应用必须保留 Babel 插件——这些插件会先于 Metro 插件运行,因此 React Compiler 会先处理 useVariants
    • Re.Pack:react-native-unistyles/repack-plugin 提供的 RepackUnistylePlugin

    如果没有使用其中任何一种,样式将不会响应变化。

  4. 仅从 react-native-unistyles 导入 StyleSheet——它为所有 RN StyleSheet API 提供 polyfill(hairlineWidth、compose、flatten、absoluteFill)。替换所有 import { StyleSheet } from 'react-native'。

  5. 必须先调用 styles.useVariants(),再访问依赖变体的样式——像使用 React Hook 一样对待它(放在组件顶部)。始终传入对象:在原生平台上,useVariants(undefined) 会报错;使用 {} 选择 default 变体。

  6. 优先使用 StyleSheet.create(theme => ...),而非 useUnistyles()——主题函数不会触发重新渲染;每当你读取的 theme/rt 值发生变化时,useUnistyles() 都会触发重新渲染(切勿在那里读取 rt.insets.ime——它会在每次键盘帧变化时触发重新渲染)。

  7. 必须先调用 StyleSheet.configure(),再调用任何 StyleSheet.create()——通常在应用入口点中、任何组件渲染之前调用。

  8. 动态函数参数必须可序列化——Unistyles 会将它们存储在 C++ 中,并在主题/运行时变化时重新运行函数。函数会被丢弃;Date/Map/Set/类实例会变成普通对象。请传入原始值/普通对象(例如 date.getTime())。

决策树

选择样式方案
Need theme/runtime in styles?
├─ YES → StyleSheet.create((theme, rt) => ...)     [zero re-renders]
└─ NO  → StyleSheet.create({ ... })                [static styles]

Need theme values as non-style props?
├─ YES → withUnistyles(Component, (theme, rt) => ({ propName: theme.value }))
└─ NO  → Pass Unistyles styles via style prop directly

Need theme/runtime in component logic (not just styles)?
├─ YES → useUnistyles() hook                        [re-renders when read values change]
└─ NO  → Use StyleSheet.create with theme function
第三方组件集成
Passing a Unistyles style to `contentContainerStyle` (ScrollView/FlatList)?
├─ YES → withUnistyles(ScrollView) — auto-maps style + contentContainerStyle
└─ NO  → react-native / react-native-reanimated view with a `style` prop?
         ├─ YES → Pass Unistyles styles directly (Babel swaps in ref-borrowing factories)
         └─ NO  → Third-party view built on RN components (in node_modules)?
                  ├─ YES → Metro integration: works as-is (node_modules are covered)
                  │        Babel plugin: add its path to autoProcessPaths (e.g. 'some-lib/src/components')
                  └─ Still not updating / needs theme-derived props (color, size, ...)?
                     ├─ YES → withUnistyles(Component, (theme, rt) => ({ prop: theme.value }))
                     └─ Last resort → useUnistyles() (re-renders the component)

Your own files outside `root` (monorepo package) not updating?
→ autoProcessImports: ['@my-org/styles']  (force-processes any file importing it; not needed with the Metro integration)

参考文件

评论

支持 Markdown