Inheriting styles in React Native components

When creating React Native components it is a good idea to think about reusability. It is common to make components that have some base style, but that can also be styled upon use. As we will see, we can leverage some useful JavaScript features to achieve this in a clean way.

In React Native we use the style prop to declare our styles, essentially emulating the way it’s done on the web but with some differences, mainly that it is written in camel case. Another thing to note is that we need to pass an object with styles (thats why we need the double {{}} in the style prop):

const MyComponent = (props) => {
return <Text style={{backgroundColor: 'green'}}>{props.title}</Text>
}
<MyComponent title="Hello world"/>

Now say we want to pass some custom styles to this component when we use it:

<MyComponent title="Hello world" style={{backgroundColor: 'red'}}/>

The style being passed will be available under props.style in the component. But how do we merge the styles that we passed with the style already in the component?

First we can use ES6 object destructuring, where we lift out the style and title from the props object. To then merge our styles we can use the ES6 spread syntax to spread the contents of the style object into the object being passed to the style prop in the component:

const MyComponent = ({style, title}) => {
return <Text style={{backgroundColor: 'green', ...style}}>{title}</Text>
}

What happens is that we pass one new object containing all our styles to the style prop. This works, but there is a better way:

const MyComponent = ({style, title}) => {
return <Text style={[{backgroundColor: 'green'}, style]}>{title}</Text>
}

Instead of passing one object containing all our styles we are now passing an array of style objects to the style prop. What we gain is precedence: the last added styles object will be evaluated last, which is desired if we intend for the passed styles to be inherited by the component.

Furthermore, we are now able to add as many style objects as we want and still maintain readability:

const MyComponent = ({style, title}) => {
return <Text style={[{backgroundColor: 'green'}, styles.myText, style]}>{title}</Text>
}
const styles = StyleSheet.create({
myText: {
color: 'white'
}
})

What if we waned to pass additional props to our component? Do we have to lift our each one using destructuring to make them available inside out component? No, there is an easier way:

const MyComponent = ({style, title, ...rest}) => {
return <Text {...rest} style={[{backgroundColor: 'green'}, styles.myText, style]}>{title}</Text>
}
const styles = StyleSheet.create({
myText: {
color: 'white'
}
})

...
<MyComponent title="Hello world" style={{backgroundColor: 'red'}} onPress={() => console.log('Howdy')} />

The ...rest will make any other props available in the function. These can then be spread using {...rest} onto the component that’s being returned. This way we can use the onPress prop and make it work in our component.

Hope this was helpful, stay tuned for more! And don’t forget to follow!

Javascript developer. Passionate learner.