Fully typed hooks and utility functions for the React Native StyleSheet API

Overview

react-native-style-utilities

Fully typed hooks and utility functions for the React Native StyleSheet API


npm i react-native-style-utilities

ESLint Setup

If you're using the eslint-plugin-react-hooks plugin, add the following to your .eslintrc.js:

"react-hooks/exhaustive-deps": [
  "error",
  {
    additionalHooks: "(useStyle|useFlatStyle)",
  },
],


useStyle

A hook to memoize dynamic styles.

See "Memoize!!! 💾 - a react (native) performance guide"

Objects

By using useStyle the object { height: number } gets memoized and will only be re-created if someDynamicValue changes, resulting in better optimized re-renders.

Bad

return <View style={{ height: someDynamicValue }} />

Good

const style = useStyle(() => ({ height: someDynamicValue }), [someDynamicValue])

return <View style={style} />

Arrays

useStyle can also be used to join arrays together, also improving re-render times.

Bad

return <View style={[styles.container, props.style, { height: someDynamicValue }]} />

Good

const style = useStyle(
  () => [styles.container, props.style, { height: someDynamicValue }],
  [props.style, someDynamicValue]
);

return <View style={style} />


useFlatStyle

Same as useStyle, but flattens ("merges") the returned values into a simple object with StyleSheet.flatten(...).

See "Memoize!!! 💾 - a react (native) performance guide"

const style1 = useStyle(
  () => [styles.container, props.style, { height: someDynamicValue }],
  [props.style, someDynamicValue]
);
style1.borderRadius // <-- does not work, `style1` is an array!

const style2 = useFlatStyle(
  () => [styles.container, props.style, { height: someDynamicValue }],
  [props.style, someDynamicValue]
);
style2.borderRadius // <-- works, will return 'number | undefined'


findStyle

A helper function to find a given style property in any style object without using expensive flattening (no StyleSheet.flatten(...)).

function Component({ style, ...props }) {
  const borderRadius = style.borderRadius // <-- does not work, style type is complex
  const borderRadius = findStyle(style, "borderRadius") // <-- works, is 'number | undefined'
}
You might also like...

Built a covid-19 trcaker app using React.js implementing hooks and materail UI

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

Dec 21, 2021

Add multiplayer presence (live cursors/avatars) to your react application using yjs and hooks

y-presence Easy way to add presence (live cursors/avatars) to any react application using react hooks. Installation yarn add y-presence # or npm i y-p

Dec 29, 2022

React Hooks — 👍

Collaborative editing for your app. Support on Kickstarter! 👍 react-use Collection of essential React Hooks. Port of libreact. Translations: 🇨🇳 汉语

Jan 3, 2023

React Hooks library for remote data fetching

React Hooks library for remote data fetching

Introduction swr.vercel.app SWR is a React Hooks library for remote data fetching. The name “SWR” is derived from stale-while-revalidate, a cache inva

Jan 4, 2023

React Hooks tutorial for beginners.

React Hooks for Beginners git clone url Clone into the repo code react-hooks Open the folder in VS Code npm install Install the dependencies npm sta

Oct 10, 2022

A custom ESLint rule to allow static deps in React Hooks ⚛️

eslint-plugin-react-hooks-static-deps A custom ESLint rule to allow static deps in React Hooks ⚛️ Motivation react-hooks/exhaustive-deps is a really n

Apr 5, 2022

A personal project, made with React, React Native, Typescript and some of the most used front-end libraries.

A personal project, made with React, React Native, Typescript and some of the most used front-end libraries.

A personal project, made with React, React Native, Typescript and some of the most used front-end libraries.

Jul 23, 2022

PDF-to-TEXT using Rest7 API REACT-NATIVE

PDF-to-TEXT using Rest7 API REACT-NATIVE

PDF-to-TEXT-using-Rest7-API-REACT-NATIVE- I have made a Demo App to select PDF from documents and convert it into text than Display in ( component) us

Nov 22, 2022

Accessible, unstyled, open-sourced, and fully functional react component library for building design systems

DORAI UI Accessible, unstyled, open-sourced and fully functional react component library for building design systems Documentation site coming soon St

Dec 30, 2022
Comments
  • Discussion on adding StyleSheet.create replacement which accepts StyleProp<T>

    Discussion on adding StyleSheet.create replacement which accepts StyleProp

    Annoyingly, StyleSheet.create only accepts named styles -> AnyStyle map. This means if you have common utilities styles, you have to spread them into each style. Here's what I mean:

    // Shared example for bgColor
    const bgColor = {
      GREEN: { backgroundColor: '#238636' },
      WHITE: { backgroundColor: '#fff' },
    }
    
    // Usage
    const style = StyleSheet.create({
      greenHeader: { ...bgColor.GREEN, ...padding.p4 },
      whitePage: { ...bgColor.WHITE, ...padding.p4, ...padding.pb6 },
    })
    

    I don't think the runtime cost of spreading likely worth consideration. I mainly just find it annoying. Since StyleSheet.create is just an identity, I created a similar function that defines NamedStyles in terms of StyleProp instead of any style:

    type CreateNamedStyles<T> = { readonly [P in keyof T]: StyleProp<ViewStyle | TextStyle | ImageStyle> }
    const createStyle = <T extends CreateNamedStyles<any>>(styles: T): T => styles
    
    // Usage
    const style = createStyle({
      greenHeader: [bgColor.GREEN, padding.p4],
      whitePage: [bgColor.WHITE, padding.p4, padding.pb6],
    })
    

    It's pretty trivial, so I'm curious what your thoughts are and if you think it's worth adding? Just like StyleSheet.create it's basically just a type helper at this point, but it makes composition of static styles easier.

    Edit: I played around a bit and createStyles is a bit unintuitive, since React Native doesn't recursively parse styles. So I basically scrapped it in favor of my createFlatStyles implementation. It has the same initial overhead as using spread, it's just easier to compose. If you think it's useful, I'll open a PR.

    opened by bfricka 2
  • What is the best way to benchmark?

    What is the best way to benchmark?

    Hi @mrousavy,

    In my app, I rely heavily on "inline" styles similar to what Tailwind does for the web but in RN. So I have a lot of arrays like:

    <View style={[tw.f[1], tw.bg.red[500]]} />
    // which is the same as {flex: 1, backgroundColor: "some hex for the special red color"}
    

    so I got curious about possible perf penalties of that approach and started investigating if wrapping all those arrays in useMemo would be beneficial.

    Trying a super-blunt test with rendering 10k views showed, surprisingly that useMemo performs worse in terms of memory while not giving any speed benefit at all, either if you render static styles or dynamic ones (which depends on some prop).

    So I'm curious what was your take on that? Did you perform any benchmarks on your own?

    Here is the code for the harness, which is pretty basic:

    import React, {
      useEffect,
      useState,
      Profiler,
      ProfilerOnRenderCallback,
    } from 'react';
    import { View, ScrollView } from 'react-native';
    import performance from 'react-native-performance';
    
    
    // test cases, see later
    import Test1 from './Test1';
    import Test2 from './Test2';
    
    const traceRender: ProfilerOnRenderCallback = (
      id, // the "id" prop of the Profiler tree that has just committed
      phase, // either "mount" (if the tree just mounted) or "update" (if it re-rendered)
      actualDuration, // time spent rendering the committed update
      baseDuration, // estimated time to render the entire subtree without memoization
      startTime, // when React began rendering this update
      commitTime, // when React committed this update
      interactions // the Set of interactions belonging to this update
    ) =>
      performance.measure(id, {
        start: performance.timeOrigin + startTime,
        duration: actualDuration,
      });
    
    const formatValue = (value: number, unit?: string) => {
      switch (unit) {
        case 'ms':
          return `${value.toFixed(1)}ms`;
        case 'byte':
          return `${(value / 1024 / 1024).toFixed(1)}MB`;
        default:
          return value.toFixed(1);
      }
    };
    
    function App() {
      let [flip, setFlip] = useState(true);
    
      useEffect(() => {
        //let metrics = performance.getEntriesByName('App.render()');
        //let metric = metrics[metrics.length - 1];
        // console.log(formatValue(metric.duration, undefined));
    
        requestAnimationFrame(() => {
          setFlip((s) => !s);
        });
      }, [flip]);
    
      return (
        // uncomment to see traces
        //<Profiler id="App.render()" onRender={traceRender}>
        <ScrollView style={{ flex: 1, paddingVertical: 40, paddingHorizontal: 20 }}>
          <View
            style={{
              flex: 1,
              flexDirection: 'row',
              flexWrap: 'wrap',
              padding: 4,
              backgroundColor: flip ? 'green' : 'red',
            }}>
            <Test1 isGreen={!flip} />
          </View>
        </ScrollView>
        //</Profiler>
      );
    }
    
    export default App;
    

    Test1.tsx

    import React from 'react';
    import { View } from 'react-native';
    
    export default ({ isGreen }) => {
      return (
        <>
          <View
            style={{
              height: 4,
              width: 4,
              margin: 4,
              backgroundColor: isGreen ? 'green' : 'red',
            }}
          />
    ...9999 more views like that
    

    Test2.tsx

    import React, { useMemo } from 'react';
    import { View } from 'react-native';
    
    export default ({ isGreen }) => {
      return (
        <>
          <View
            style={useMemo(
              () => ({
                height: 4,
                width: 4,
                margin: 4,
                backgroundColor: isGreen ? 'green' : 'red',
              }),
              [isGreen]
            )}
          />
    ...9999 more views like that
    

    Both tests ran on iPhoneXS and have the same perf metrics (around 4fps with static styles, and 1-2 fps with dynamic, and 50-55 fps on UI) But non-memoized version uses around 150mb, while memoized 200

    opened by somebody32 3
Owner
Marc Rousavy
they call me ranch cause I be dressing
Marc Rousavy
📋 React Hooks for forms validation (Web + React Native)

English | 繁中 | 简中 | 日本語 | 한국어 | Français | Italiano | Português | Español | Русский | Deutsch | Türkçe Features Built with performance and DX in mind

React Hook Form 32.4k Dec 29, 2022
🎉 toastify-react-native allows you to add notifications to your react-native app (ios, android) with ease. No more nonsense!

toastify-react-native ?? toastify-react-native allows you to add notifications to your react-native app (ios, android) with ease. No more nonsense! De

Zahid Ali 29 Oct 11, 2022
React Native's Global Alert Component that can be fully customized and without the need of a state.

?? React Native Easy Alert React Native Easy Alert Component. Watch on youtube Easy Alert example app. React Native's Global Alert Component that can

null 9 Feb 21, 2022
Simple React Native marquee component,fully implemented using reanimated v2,support to iOS/Android/Web.

@react-native-reanimated-community/react-native-reanimated-marquee Simple React Native marquee component,fully implemented using reanimated v2,support

react-native-reanimated-community 6 Sep 25, 2022
React Native popup tip utility

react-native-tip React Native Tip is a simple package inspired in MaterialUI-Tooltip that helps you to show a quick tip to the user and highlight some

Maicon Gilton de Souza Freire 42 Jan 5, 2023
null 136 Dec 30, 2022
React components and hooks for creating VR/AR applications with @react-three/fiber

@react-three/xr React components and hooks for creating VR/AR applications with @react-three/fiber npm install @react-three/xr These demos are real,

Poimandres 1.4k Jan 4, 2023
Redux-Toolkit example with React Hooks CRUD Application, Axios, Rest API, Bootstrap

Redux-Toolkit CRUD example with React Hooks, Axios & Web API Build Redux-Toolkit CRUD application with React Hooks and Rest API calls in that: Each it

null 69 Dec 27, 2022
⚛️ Hooks for building fast and extendable tables and datagrids for React

Hooks for building lightweight, fast and extendable datagrids for React Enjoy this library? Try them all! React Query, React Form, React Charts Visit

Tanner Linsley 20.3k Jan 3, 2023
⚛️ Hooks for fetching, caching and updating asynchronous data in React

Hooks for fetching, caching and updating asynchronous data in React Enjoy this library? Try the entire TanStack! React Table, React Form, React Charts

Tanner Linsley 32.1k Jan 9, 2023