关于 react-native-unistyles-v3
react-native-unistyles-v3 是面向 React Native 开发者的样式技能,介绍如何使用 Unistyles v3 构建主题化和响应式界面。它强调通过 C++ 核心和构建时处理实现样式更新而不触发重新渲染。
主要功能
- 01静态与主题响应式样式
- 02主题和断点配置
- 03基于属性的样式变体
- 04将主题值映射到组件属性
- 05Babel、Metro 与 Re.Pack 集成
适用场景
- 01为应用添加明暗主题
- 02按屏幕尺寸切换布局
- 03为组件实现尺寸变体
- 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.mdcommon-issues.mdsetup-guide.mdstyling-patterns.mdthird-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 所需)
工作流
- 先阅读用户的代码 — 了解当前配置、导入和样式方案
- 识别意图 — 新建配置、添加主题、响应式设计、修复问题等
- 应用 v3 模式 — 使用本技能中的正确 API;需要详细信息时请查阅参考文件
- 验证正确性 — 检查是否违反关键规则(展开、桶文件重新导出等)
快速参考
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 })} />
关键规则
-
绝不要展开样式——
{...styles.x}会破坏 C++ 代理绑定。始终使用数组语法:[styles.x, styles.y]或[styles.x, { marginTop: 10 }] -
绝不要从 barrel 文件重新导出 StyleSheet——直接从
react-native-unistyles导入。在root之外,Babel 插件只能识别通过该导入(或autoProcessImports)调用的StyleSheet.create,因此重新导出会导致检测悄然失效。(Metro 集成也能检测从你自己的模块重新导出的情况,但直接导入在任何地方都能正常工作。) -
必须使用构建时集成——以下任选其一:
- 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
如果没有使用其中任何一种,样式将不会响应变化。
- Babel 插件(默认):在 babel.config.js 中使用
-
仅从
react-native-unistyles导入 StyleSheet——它为所有 RN StyleSheet API 提供 polyfill(hairlineWidth、compose、flatten、absoluteFill)。替换所有import { StyleSheet } from 'react-native'。 -
必须先调用
styles.useVariants(),再访问依赖变体的样式——像使用 React Hook 一样对待它(放在组件顶部)。始终传入对象:在原生平台上,useVariants(undefined)会报错;使用{}选择default变体。 -
优先使用
StyleSheet.create(theme => ...),而非useUnistyles()——主题函数不会触发重新渲染;每当你读取的theme/rt值发生变化时,useUnistyles()都会触发重新渲染(切勿在那里读取rt.insets.ime——它会在每次键盘帧变化时触发重新渲染)。 -
必须先调用
StyleSheet.configure(),再调用任何StyleSheet.create()——通常在应用入口点中、任何组件渲染之前调用。 -
动态函数参数必须可序列化——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)
参考文件
- 设置、安装、Babel 插件、Metro 集成、Re.Pack、TypeScript、测试、Expo Router:阅读 references/setup-guide.md
- 每个导出的完整 API:阅读 references/api-reference.md
- 代码模式:主题、变体、断点、Web、SSR、Reanimated:阅读 references/styling-patterns.md
- withUnistyles、autoProcessPaths/Imports、React Compiler、Reanimated、edge-to-edge、冻结屏幕、FlatList:阅读 references/third-party-integration.md
- 基于 150 多个 GitHub 问题整理的故障排查与解决方案:阅读 references/common-issues.md