Skip to content

Commit

Permalink
Merge pull request #27 from levibuzolic/memoize-styles
Browse files Browse the repository at this point in the history
RFC: Memoize style objects to prevent re-renders of memoized components
  • Loading branch information
jpudysz authored Oct 13, 2023
2 parents eca3c2c + d127771 commit ce5cd32
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 19 deletions.
7 changes: 1 addition & 6 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,7 @@ export const App: React.FunctionComponent = () => {

return (
<UnistylesTheme theme={appTheme}>
<Examples.Extreme
onToggleTheme={() => setTheme(prevState => prevState === Theme.Light
? Theme.Dark
: Theme.Light
)}
/>
<Examples.Memoization />
</UnistylesTheme>
)
}
54 changes: 54 additions & 0 deletions example/src/examples/Memoization.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react'
import { Text, View, type StyleProp, type TextStyle, Button } from 'react-native'
import { createStyleSheet, useStyles } from '../styles'

export const Memoization: React.FunctionComponent = () => {
const { styles } = useStyles(stylesheet)
const [ count, setCount ] = React.useState(0)

return (
<View style={styles.container}>
<Memoized text="With breakpoints" style={styles.withBreakpoints} />
<Memoized text="No breakpoints" style={styles.noBreakpoints} />
<Memoized text="Static" style={staticStyles.static} />
<Button title={`Re-render (${count})`} onPress={() => setCount(count => count + 1)} />
</View>
)
}

const Memoized = React.memo<{text: string; style: StyleProp<TextStyle>}>(({ text, style }) =>
<Text style={style}>{text} ({useRenderCount()})</Text>
)

const useRenderCount = () => {
const count = React.useRef(0)
count.current++

return count.current
}

const stylesheet = createStyleSheet({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
alignContent: 'space-between',
resizeMode: 'contain'
},
withBreakpoints: {
fontSize: 18,
color: {
xs: 'red',
md: 'blue'
}
},
noBreakpoints: {
fontSize: 18
}
})

const staticStyles = createStyleSheet({
static: {
fontSize: 18
}
})
1 change: 1 addition & 0 deletions example/src/examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export { Theme } from './Theme'
export { Breakpoints } from './Breakpoints'
export { MediaQueries } from './MediaQueries'
export { Extreme } from './Extreme'
export { Memoization } from './Memoization'
11 changes: 6 additions & 5 deletions src/createUnistyles.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useContext } from 'react'
import { useContext, useMemo } from 'react'
import { StyleSheet } from 'react-native'
import type {
Breakpoints,
Expand Down Expand Up @@ -36,12 +36,13 @@ export const createUnistyles = <B extends Breakpoints, T = {}>(breakpoints: B) =
}
}

const parsedStyles = typeof stylesheet === 'function'
const parsedStyles = useMemo(() => typeof stylesheet === 'function'
? stylesheet(theme)
: stylesheet
: stylesheet, [theme, stylesheet])

const breakpoint = getBreakpointFromScreenWidth<B>(screenSize.width, sortedBreakpointEntries)

const dynamicStyleSheet = Object
const dynamicStyleSheet = useMemo(() => Object
.entries(parsedStyles)
.reduce((acc, [key, value]) => {
const style = value as CustomNamedStyles<ST, B>
Expand All @@ -57,7 +58,7 @@ export const createUnistyles = <B extends Breakpoints, T = {}>(breakpoints: B) =
...acc,
[key]: parseStyle<ST, B>(style, breakpoint, screenSize, sortedBreakpointEntries)
})
}, {} as ST)
}, {} as ST), [breakpoint, screenSize, parsedStyles])

return {
theme,
Expand Down
9 changes: 1 addition & 8 deletions src/hooks/useDimensions.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import { useWindowDimensions } from 'react-native'
import type { ScreenSize } from '../types'

export const useDimensions = (): ScreenSize => {
const { width, height } = useWindowDimensions()

return {
width,
height
}
}
export const useDimensions = (): ScreenSize => useWindowDimensions()

0 comments on commit ce5cd32

Please sign in to comment.