React Native Unistyles Unicorn

Introduction

I’m thrilled to announce the first beta release of Unistyles 3.0!

We’re incredibly excited about this update, as it brings a lot of new features and introduces significant changes to how the Unistyles engine works. One of the biggest improvements is the elimination of unnecessary re-renders throughout your app, making your development process smoother and more efficient than ever before!

No re-renders

Before Unistyles 3.0, any time a native change was emitted, Unistyles would trigger a re-render across your app. While this approach worked to some extent, it often led to unnecessary re-renders and performance lags, especially in apps with a large number of styles or complex structures. This could result in a less-than-ideal user experience, as the app would slow down or become less responsive.

-import { useStyles, createStyleSheet } from 'react-native-unistyles'

With the new core, we’ve removed the useStyles hook and instead rely on the Shadow Tree and C++ for style management. What this means is that you no longer need to use hooks to access your parsed styles. Essentially, we’re adopting a similar approach to what CSS does for the web—styles are managed more efficiently and independently from the components, resulting in a faster, cleaner experience.

If you want to learn more how Unistyles works, check out this detailed guide.

StyleSheet parity

Unistyles now fully follows the StyleSheet API, making it a true superset of React Native’s StyleSheet. We believe this change will make the transition to Unistyles even smoother and more intuitive for developers, as it maintains familiarity while offering enhanced functionality.

MyComponent.tsx
import { View, Text } from 'react-native'
import { StyleSheet } from 'react-native-unistyles'

export const MyComponent = () => {
    // no more hooks!

    return (
        <View style={styles.container}>
            <Text style={styles.text}>
                Hello from Unistyles 3.0!
            </Text>
        </View>
    )
}

const styles = StyleSheet.create(theme => ({
    container: {
        flex: 1,
        backgroundColor: theme.colors.background
    },
    text: {
        color: theme.colors.typography
    }
}))

And if you ever decide Unistyles isn’t for you, you can easily revert to the React Native version!

Compound variants

This was the natural next step after introducing variants in Unistyles 2.0. Now, you can customize your StyleSheet even further by adding extra conditions that apply additional styles, giving you more control and flexibility in how your app’s UI behaves.

CompoundVariants.ts
const styles = StyleSheet.create(theme => ({
    themedText: {
        variants: {
            isBold: {
                true: {
                    fontWeight: 'bold'
                }
            },
            color: {
                primary: {
                    color: theme.colors.primary
                },
                secondary: {
                    color: theme.colors.secondary
                },
                link: {
                    color: theme.colors.link
                }
            }
        },
        compoundVariants: [
            {
                isBold: true, // when isBold is true
                color: 'link', // and color is link
                // apply following styles
                styles: {
                    textDecorationLine: 'underline',
                    fontSize: 12
                }
            }
        ]
    }
})

Shadow Tree Updates

We’re especially proud of the new algorithm that updates your views from C++ via the Shadow Tree.

Unistyles now analyzes your style dependencies. Only if one of 14 events occurs, and the affected style is linked to the event, it will be recalculated and updated from C++ — all without triggering a re-render in React. This drastically improves performance by reducing unnecessary updates. We’ve also created a dedicated guide to explain how Shadow Tree updates work. Feel free to learn more about it!

How Unistyles works?

Powered by Nitro Modules

Unistyles is now powered by Nitro Modules! This new foundation makes Unistyles fully type-safe, with strong typing from TypeScript all the way through C++ to Kotlin and Swift. But that’s not all:

These improvements help streamline performance and maintainability, allowing us to push the boundaries of what’s possible in cross-platform development.

Custom Web Parser / Pseudo classes

We’ve moved away from the React Native Web parser and built a custom solution specifically tailored to Unistyles. Our new parser is designed to align perfectly with our syntax, giving you access to CSS classes, web features, pseudo-classes, and much more, all right out of the box.

Yes, you read that right! You can now use pseudo-classes directly from your StyleSheet.

Pseudo.tsx
const styles = StyleSheet.create(theme => ({
    button: {
        backgroundColor: theme.colors.button,
        _web: {
            _hover: {
                backgroundColor: theme.colors.hovered,
            },
            _before: {
                content: '"🦄"',
            }
        }
    },
}))

Every style for the web will now be converted into a valid CSS class, and yes, media queries are included as well! This ensures that your styles work seamlessly across both web and native environments.

Attaching custom classes to your styles

If you want to experiment with Tailwind or add complex styles from CSS files, you can now easily attach custom classes to your styles. This gives you the flexibility to combine the power of Unistyles with the simplicity of existing CSS frameworks or custom styles.

CssClasses.tsx

const styles = StyleSheet.create({
    container: {
        flex: 1,
        _web: {
            _classNames: 'container mx-auto other-custom-class'
        }
    }
})

IME insets support

With the new Unistyles architecture, we’ve added support for the IME inset. This inset tracks the keyboard height in real-time, allowing you to dynamically adjust your UI based on the keyboard’s presence.

By using this inset in your style, it will automatically register for future updates, all while skipping any re-renders of your views.

AvoidKeyboard.tsx

import { TextInput, View } from 'react-native'
import { StyleSheet } from 'react-native-unistyles'

const KeyboardAvoidingView = () => {
    return (
        <View style={styles.container}>
            <TextInput style={styles.input} />
        </View>
    )
}

const styles = StyleSheet.create((theme, rt) => ({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'flex-end',
        backgroundColor: theme.colors.backgroundColor,
        paddingHorizontal: theme.gap(2),
        paddingTop: rt.insets.top,
        transform: [
            {
                translateY: rt.insets.ime * -1
            }
        ]
    },
    input: {
        width: '100%',
    }
}))

Summary

That’s just the tip of the iceberg. We strongly encourage you to browse the new documentation where you’ll find guides, API references, and more articles explaining how everything works.

We look forward to your feedback in the coming weeks as we continue to make Unistyles even more powerful and flexible. We’re excited to see what you’ll create with Unistyles!

Did you enjoy the post?

Subscribe to the React Native Crossroads newsletter

Subscribe now

Do you want to support me even more?

github-mona

Sponsor me on Github

kofi

Buy me a coffee

x-twitter

Share it on Twitter

Jacek Pudysz | Copyright ©2024 | All rights reserved

Built with Astro 🚀