A lot of React Native developers come from a web background. They're used to working with CSS and since React Native styling is basically a stripped down version of CSS, it means they quickly get used to it. There is however one feature in React Native that I find extremely useful which cannot be found on the web - so a lot of devs don't even realize it exists. I'm talking about the aspectRatio style prop.
So what is it? Why should you use it? Well, imagine this scenario. You want to create a scrollable screen filled with some images. All the images are perfectly square and take up the width of the screen.
So how do you get the height of the image? That's easy - you just import { Dimensions } from "react-native"
and you use the window width for both the width and height, right? Like this:
function Card({ item: uri }) {
const { width } = Dimensions.get("window");
return (
<Image
source={{ uri }}
style={{
width: width,
height: width
}}
/>
);
}
You use a FlatList to render the cards like this and even add a fancy separator.
<FlatList
style={{ flex: 1 }}
ItemSeparatorComponent={() => <View style={{ height: 16 }} />}
data={images}
renderItem={Card}
keyExtractor={image => image}
/>
So, this works fine, but let's say that sometime later, you have to do some tweaks and add some horizontal padding to the FlatList - here's what you'll get.
<FlatList
style={{ flex: 1 }}
contentContainerStyle={{ padding: 64 }} /* ADDED THIS */
ItemSeparatorComponent={() => <View style={{ height: 16 }} />}
data={images}
renderItem={Card}
keyExtractor={image => image}
/>
Our UI breaks. That's because the images are as wide as our screen, and with the padding they extend beyond the screen. The issue is we're using Dimensions to set the width - which we obviously don't want as it makes our components fragile.
So what we need to do is make the image take all available width and still keep the aspect ratio 1:1. The aspectRatio
style prop does just that.
Simply use it like this:
function Card({ item: uri }) {
return (
<Image
source={{ uri }}
style={{
width: "100%",
aspectRatio: 1
}}
/>
);
}
If the parents View has it's alignItems style prop set to stretch
(this is the default) you don't even have to specify width: "100%"
as all the children will stretch to fill all the available width.
function Card({ item: uri }) {
return (
<Image
source={{ uri }}
style={{ aspectRatio: 1 }}
/>
);
}
Here's the result.
Use aspectRatio
wherever you can and avoid grabbing the window width using the Dimensions API. aspectRatio
can make your components better adapt to change and in turn make your UI more stable.
There is one caveat - this doesn't (yet) work with react-native-web, so if you're using that, it's best to avoid it.
Top comments (2)
Very helpful!
Thank you for article!