Giter VIP home page Giter VIP logo

react-native-responsive-image-view's Introduction

react-native-responsive-image-view

React Native component for scaling an Image within the parent View

npm Version Build Status Code Coverage

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

Using npm:

npm install react-native-responsive-image-view

This package also depends on react and react-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 function MyComponent({ imageUri }) {
  return (
    <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 render prop, 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 function MyComponent({ 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:

  1. component
  2. render
  3. function as children
  4. non-functional children (render children normally)
  5. 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

See this blog post about 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 Expo Go, or enable the Preview option to use the in-browser simulators!

Note: Snack's underlying build system, snackager, cannot currently handle some TypeScript features used in this library, so the version showcased in the playground is pinned to the latest pre-TypeScript implementation. We hope the Expo team can resolve this soon, but it should still provide a useful environment to try out the library in the meantime.

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.

LICENSE

MIT

react-native-responsive-image-view's People

Contributors

dependabot[bot] avatar github-actions[bot] avatar renovate-bot avatar renovate[bot] avatar wkovacs64 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

react-native-responsive-image-view's Issues

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/ci.yml
  • actions/checkout v4
  • actions/setup-node v4
  • actions/checkout v4
  • actions/setup-node v4
  • actions/checkout v4
  • actions/setup-node v4
  • codecov/codecov-action v4
  • actions/checkout v4
  • actions/setup-node v4
  • actions/checkout v4
  • actions/setup-node v4
  • changesets/action v1
npm
package.json
  • @babel/core 7.24.5
  • @babel/plugin-proposal-class-properties 7.18.6
  • @changesets/changelog-github 0.5.0
  • @changesets/cli 2.27.1
  • @testing-library/react-native 12.5.0
  • @types/jest 29.5.12
  • @types/react 18.2.79
  • @types/react-test-renderer 18.3.0
  • @wkovacs64/prettier-config 3.0.3
  • babel-jest 29.7.0
  • doctoc 2.2.1
  • eslint 8.57.0
  • eslint-plugin-wkovacs64 16.2.0
  • jest 29.7.0
  • jest-watch-typeahead 2.2.2
  • metro-react-native-babel-preset 0.77.0
  • npm-run-all2 6.1.2
  • prettier 3.2.5
  • react 18.2.0
  • react-dom 18.2.0
  • react-native 0.74.1
  • react-native-builder-bob 0.23.2
  • react-test-renderer 18.2.0
  • rimraf 5.0.5
  • ts-node 10.9.2
  • typescript 5.0.4
  • react >=16.8.3
  • react-native >=0.59.0
nvm
.nvmrc
  • node 20

  • Check this box to trigger a request for Renovate to run again on this repository

I found several bug

The picture is too large to show,more than 1m. Can't image and text be enabled? thanks!

Retry functionality

Have useResponsiveImageView to return a call back that can be used to trigger retry load. The loading may fail for various reasons, so having retry functionality is a user-friendly thing.

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.