react-native-responsive-image-view
react-native-responsive-image-view copied to clipboard
React Native component for scaling an Image within the parent View
react-native-responsive-image-view
React Native component for scaling an Image within the parent View
The problem
You want to display an image in your React Native app that fills the width of
its container and scales its height according to the aspect ratio of the image.
If you're coming from front-end web development, you may be familiar with
Bootstrap 3's img-responsive class or manually applying max-width: 100% and
height: auto to an image. Unfortunately, auto is not a valid value for
height in React Native, so that technique doesn't quite translate.
This solution
This calculates the aspect ratio of your image for you (or uses a fixed value,
if you supply one) and provides you with the appropriate props to apply to a
View container and an Image inside it which will produce the results you're
looking for. The secret sauce is setting both the height and width
attributes of the style prop on the Image to 100% and wrapping it with a
View that has its aspectRatio style property set to match the
aspect ratio you want. The package provides both a render prop
component and a custom hook.
Table of Contents
- Installation
- Usage
- Component
- Hook
- Input
- Basic Inputs
- onLoad
- onError
- source
- Advanced Inputs
- aspectRatio
- Component-only Inputs
- Render Prop Function
- component
- render
- children
- Render Prop Function
- Basic Inputs
- Output
- prop getters
getViewPropsgetImageProps
- state
- utils
- prop getters
- Examples
- Snack Playground
- Inspiration
- Other Solutions
- LICENSE
Installation
Using yarn:
yarn add react-native-responsive-image-view
Or, npm:
npm install react-native-responsive-image-view
This package also depends on
react,prop-types, andreact-native. Please make sure you have those installed as well.
Usage
As mentioned above, this package includes both a render prop component (the default export) and a custom hook (a named export). They provide the same functionality, so choose whichever is most appropriate for your project.
Component
import React from 'react';
import { Image, View } from 'react-native';
import ResponsiveImageView from 'react-native-responsive-image-view';
export default ({ imageUri }) => (
<ResponsiveImageView source={{ uri: imageUri }}>
{({ getViewProps, getImageProps }) => (
<View {...getViewProps()}>
<Image {...getImageProps()} />
</View>
)}
</ResponsiveImageView>
);
N.B. This component doesn't render anything itself, it just calls your
render function or injected component and renders that. "Use a render
prop!" Just be sure to render the Image inside the View
in your render function.
In addition to a literal
renderprop, it also supports the component injection and function-as-children patterns if you prefer. See the Render Prop Function section for details.
Hook
import React from 'react';
import { Image, View } from 'react-native';
import { useResponsiveImageView } from 'react-native-responsive-image-view';
export default ({ imageUri }) => {
const { getViewProps, getImageProps } = useResponsiveImageView({
source: { uri: imageUri },
});
return (
<View {...getViewProps()}>
<Image {...getImageProps()} />
</View>
);
};
Input
The component takes its inputs as individual props, while the hook takes its inputs as an object (the only parameter), but the inputs themselves are primarily the same:
Basic Inputs
onLoad
function()| optional, no useful default
Called after the image has been loaded (and the aspect ratio has been calculated).
onError
function(error: string)| optional, no useful default
Called if the image could not be loaded. Called with the error message in the form of a string.
error: the error message as a string
source
number/object| required
The source for your Image. This can be a local file resource (the result of an
import or require statement) or an object containing a uri key with a
remote URL as its value.
Advanced Inputs
aspectRatio
number| control prop, default: automatically calculated from image dimensions
By default, react-native-responsive-image-view manages this value internally
based on the dimensions of the source image. However, if more control is needed,
you can pass in a fixed aspect ratio to use instead. This is useful if you want
to fit the image into a statically shaped box such as a navigation drawer
header.
Component-only Inputs
Render Prop Function
This is where you render whatever you want to based on the state of
react-native-responsive-image-view when using the component (not applicable
when using the hook). It's just a function or component, available in a few
different ways. Read Donavon West's very opinionated but informative post about
them for more information. They all receive the same props, so it
is purely a stylistic choice left up to you as the consumer.
// component injection
<ResponsiveImageView component={/* right here */} />
// render prop
<ResponsiveImageView render={/* right here */} />
// function-as-children
<ResponsiveImageView>
{/* right here */}
</ResponsiveImageView>
Choose your approach by passing one of the following props:
component
component| optional
This is rendered with an object passed in as props. Read more about the
properties of this object in the Output section.
render
function({})| optional
This is called with an object. Read more about the properties of this object in the Output section.
children
function({})| optional
This is called with an object. Read more about the properties of this object in the Output section.
N.B. Multiple render methods should not be combined, but in the event that
they are, react-native-responsive-image-view will honor the following order:
componentrender- function as
children - non-functional
children(render children normally) null(render nothing)
Output
Regardless of whether you are using the component or the hook, the results are an object containing important properties you'll need for rendering. It will be passed to the Render Prop Function when using the component, and returned from the hook invocation when using the hook. The properties of this object can be split into the following categories:
prop getters
These functions are used to apply props to the elements that you render. This
gives you maximum flexibility to render what, when, and wherever you like. You
call these on the element in question (for example:
<View {...getViewProps()})). It's advisable to pass all your props to that
function rather than applying them on the element yourself to avoid your props
being overridden (or overriding the props returned). For example:
getViewProps({ hitSlop: myHitSlop }).
| property | type | description |
|---|---|---|
getViewProps |
function({}) |
returns the props you should apply to the View (parent of Image) you render |
getImageProps |
function({}) |
returns the props you should apply to the Image (child of View) you render |
getViewProps
This method should be applied to the View you render. It is recommended that
you pass all props as an object to this method which will compose together any
of the props you need to apply to the View while preserving the ones that
react-native-responsive-image-view needs to apply to make the View behave.
There are no required properties for this method.
getImageProps
This method should be applied to the Image you render. It is recommended that
you pass all props as an object to this method which will compose together any
of the props you need to apply to the Image while preserving the ones that
react-native-responsive-image-view needs to apply to make the Image behave.
There are no required properties for this method.
state
These are values that represent the current state of the component.
| property | type | description |
|---|---|---|
loading |
boolean |
whether or not the image is currently loading |
error |
string |
an error message if the image failed to load ('' on success) |
utils
These are miscellaneous helpers that don't fit in the other major categories.
| property | type | description |
|---|---|---|
retry |
function() |
force another attempt to resolve the image dimensions |
Examples
See the examples directory for examples using both the
component and the hook.
Snack Playground
Check out the Snack Playground for an interactive experience where you can try out the various usage patterns. You can see the code run live on your own device via the Expo client, or enable the Preview option to use the in-browser simulators!
Inspiration
I was heavily inspired by react-native-flex-image
from KodeFox (see the Other Solutions section)
with regards to how to display the image to get the desired behavior. The
original implementation and API were primarily inspired by Michael
Jackson's "Use a Render Prop!" post and video,
as well as Kent C. Dodds' introduction to prop
getters.
Other Solutions
After scouring npm for solutions and trying most (if not all) of them, the best option I found was the following:
Unfortunately, it is too restrictive for my use cases. It renders the magic
<View><Image /></View> combination for you, preventing you from customizing
the layout. For example, it provides an onPress prop if you want to make the
Image touchable, but it wraps the Image in a TouchableOpacity (what if I
wanted a TouchableHighlight instead?). It also renders its own loading
indicator (an ActivityIndicator) as well as error messages (as Text). At the
end of the day, these features proved to be too opinionated.