github jpudysz/react-native-unistyles v3.8.1
Release v3.8.1

4 hours ago

What's Changed

A patch release with no breaking changes. It fixes a regression from 3.8.0: while a Reanimated animation ran, theme changes on Android landed seconds late and iOS debug builds could abort. On web, withUnistyles styles reach Gesture Handler 3 components again, and Expo Router's server output (web.output: "server") now works.

🎨 Themes and styles

  • While a Reanimated animation runs, a theme change no longer freezes the UI for several seconds on Android, and iOS debug builds no longer abort with attempts < 1024 in ShadowTree::commit. Since 3.8.0, Unistyles clones its nodes inside the commit. Reanimated commits on every frame, so each retry found a newer root, cloned and laid out the whole tree again, and lost again. A retry now reuses the tree from the previous attempt and only takes the newest root's layout constraints, so the Android rotation fix from 3.8.0 (#1347) still applies. This affected 3.8.0 only (#1365, closes #1363)

🌐 Web

  • withUnistyles styles now reach Gesture Handler 3 components (RectButton, BaseButton, BorderlessButton, RawButton, LegacyPressable, and RNGH's ScrollView, TextInput, Switch and FlatList). RNGH 3 renders a display: contents view first, and Unistyles styled that view instead of the component. Unistyles doesn't look for RNGH: its child rules now also match the only child of any display: contents view, without raising specificity. This works with both the Babel plugin and the Metro integration (#1367, closes #1366)

🖥️ Expo Router server output

  • With Expo Router's web.output: "server" (Expo SDK 58+), pages no longer return a 500 with "no theme has been selected yet". Expo Router loads a route before the +html.tsx that imports your config, so StyleSheets ran before StyleSheet.configure. On the server, a StyleSheet function created before the config is now created the first time it's used (#1368)
  • In the browser, Unistyles now takes over the server's styles on its own. +html.tsx only renders on the server, so before, nothing called hydrateServerUnistyles (#1368)
  • <Display>, <Hide> and useAnimatedVariantColor no longer use window or document while rendering on the server, which made React fall back to client rendering for those pages. On the server, <Display> and <Hide> content stays hidden until the browser renders it. The variant color switches from the server's placeholder to the real color after hydration (#1369)
  • The Expo Router guide has a new server rendering section. Render useServerUnistyles after children in +html.tsx. Otherwise each page gets the previous request's styles. The section also covers Suspense boundaries and values that differ between server and browser (#1368)
// +html.tsx
import '../unistyles' // <-- file that initializes Unistyles
import { useServerDocumentContext } from 'expo-router/html'
import { type PropsWithChildren } from 'react'
import { useServerUnistyles } from 'react-native-unistyles/server'

// Rendered after the page, so it collects the styles the page rendered
const UnistylesStyles = () => <>{useServerUnistyles({ includeRNWStyles: false })}</>

export default function Root({ children }: PropsWithChildren) {
    const { htmlAttributes, bodyAttributes, headNodes, bodyNodes } = useServerDocumentContext()

    return (
        <html {...htmlAttributes}>
            <head>{headNodes}</head>
            <body {...bodyAttributes}>
                {children}
                <UnistylesStyles />
                {bodyNodes}
            </body>
        </html>
    )
}

❤️ Contributors

Thanks to those whose PRs and reports shaped the fixes:

Full Changelog: v3.8.0...v3.8.1

Don't miss a new react-native-unistyles release

NewReleases is sending notifications on new releases.