react-native-responsive-image-view

repository·main·Indexed 18 days ago

https://github.com/wkovacs64/react-native-responsive-image-view

A React Native utility for scaling images to fill the width of a parent container while maintaining the correct aspect ratio, solving the lack of support for height: 'auto' in React Native. It provides a ResponsiveImageView component and a useResponsiveImageView hook that use a render prop pattern to provide necessary props for a container View and an Image component. Supports custom aspect ratios, loading and error states, and lifecycle callbacks like onLoad and onError.

Tokens
5.2K
Snippets
12
Records
15
Agent score
61%

What's inside react-native-responsive-image-view

  1. How ResponsiveImageView manages aspect ratios

    main

    The library solves the problem of layout shifts by ensuring the container of an image has the correct aspect ratio before the image is fully rendered.

    It works by using Image.getSize (or Image.resolveAssetSource for local resources) to fetch the actual dimensions of the image. Once dimensions are known, it calculates the aspectRatio (width / height).

    There are two ways to handle aspect ratio:

    1. Automatic: The library fetches dimensions and calculates the ratio itself. The getViewProps method then applies this ratio to the container's style.
    2. Controlled: You provide a fixed aspectRatio in the options. The library skips dimension fetching and uses your provided value immediately.

    This ensures that the View container (via getViewProps) maintains the correct proportions, preventing the UI from jumping when the image finally loads.

  2. Handle loading and error states in ResponsiveImageView

    main

    You can implement custom loading indicators and error UI by checking the loading and error properties provided by the ResponsiveImageView render prop. If an error occurs, you can use the retry function to allow the user to attempt to reload the image.

    import React from "react";
    import { ActivityIndicator, Image, Text, Button, View } from "react-native";
    import { ResponsiveImageView } from "react-native-responsive-image-view";
    
    const MyComponent = ({ imageUri }) => (
      <ResponsiveImageView source={{ uri: imageUri }}>
        {({ error, loading, retry, getViewProps, getImageProps }) => {
          if (loading) {
            return <ActivityIndicator animating={true} size="large" />;
          }
          if (error) {
            return (
              <View>
                <Text>{error}</Text>
                <Button onPress={retry} title="Retry" />
              </View>
            );
          }
          return (
            <View {...getViewProps()}>
              <Image {...getImageProps()} />
            </View>
          );
        }}
      </ResponsiveImageView>
    );
  3. Use onLoad and onError callbacks in ResponsiveImageView

    main

    ResponsiveImageView supports onLoad and onError callback props, similar to the standard React Native Image component. These are useful for triggering side effects when the image state changes.

    import React from "react";
    import { Image, View } from "react-native";
    import { ResponsiveImageView } from "react-native-responsive-image-view";
    
    class MyClassComponent extends React.Component {
      onLoad = () => {
        console.log("Image has been loaded.");
      };
    
      onError = (err) => {
        console.error(err);
      };
    
      renderImageView = ({ getViewProps, getImageProps }) => (
        <View {...getViewProps()}>
          <Image {...getImageProps()} />
        </View>
      );
    
      render() {
        const { imageUri } = this.props;
    
        return (
          <ResponsiveImageView
            onLoad={this.onLoad}
            onError={this.onError}
            source={{ uri: imageUri }}
          >
            {this.renderImageView}
          </ResponsiveImageView>
        );
      }
    }
  4. Set a fixed aspect ratio in ResponsiveImageView

    main

    To force a specific aspect ratio regardless of the source image's dimensions, provide the aspectRatio prop to ResponsiveImageView.

    import React from "react";
    import { Image, View } from "react-native";
    import { ResponsiveImageView } from "react-native-responsive-image-view";
    import headerImage from "./header.jpg";
    
    const DrawerHeader = () => (
      <ResponsiveImageView aspectRatio={16 / 9} source={headerImage}>
        {({ getViewProps, getImageProps }) => (
          <View {...getViewProps()}>
            <Image {...getImageProps()} />
          </View>
        )}
      </ResponsiveImageView>
    );
  5. Use the ResponsiveImageView component

    main

    The ResponsiveImageView component uses a render prop pattern to provide the necessary props for a responsive image layout. It does not render anything itself; instead, it calls your render function. You must render an Image inside a View within your render function to achieve the responsive effect.

    You can use the render prop, the component prop, or the children function pattern. The component honors them in this order: component > render > children (function) > children (non-functional).

    import * as React from "react";
    import { Image, View } from "react-native";
    import { ResponsiveImageView } from "react-native-responsive-image-view";
    
    function MyComponent({ imageUri }) {
      return (
        <ResponsiveImageView source={{ uri: imageUri }}>
          {({ getViewProps, getImageProps }) => (
            <View {...getViewProps()}>
              <Image {...getImageProps()} />
            </View>
          )}
        </ResponsiveImageView>
      );
    }
  6. Merge custom styles with ResponsiveImageView props

    main

    When using getViewProps and getImageProps, you can pass additional style or prop objects to these functions. The component will merge your custom props with the responsive props it calculates.

    Note: For the Image component, ResponsiveImageView will overwrite certain properties (like width or height) to ensure responsiveness, so use this pattern primarily for adding styles like padding to the container or other non-layout styles to the image.

    import React from "react";
    import { StyleSheet, Image, View } from "react-native";
    import { ResponsiveImageView } from "react-native-responsive-image-view";
    
    const styles = StyleSheet.create({
      imageContainer: {
        padding: 20, // will be merged into ResponsiveImageView View props!
      },
      image: {
        width: "50%", // will be overwritten by ResponsiveImageView Image props!
      },
    });
    
    const MyComponent = ({ imageUri }) => (
      <ResponsiveImageView source={{ uri: imageUri }}>
        {({ getViewProps, getImageProps }) => (
          <View {...getViewProps({ style: styles.imageContainer })}>
            <Image {...getImageProps({ style: styles.image })} />
          </View>
        )}
      </ResponsiveImageView>
    );
  7. Use the ResponsiveImageView component with render props

    main

    The ResponsiveImageView component uses a render prop pattern to provide calculated props for both a container View and the underlying Image. This allows you to maintain responsiveness while controlling the layout.

    Inside the render function, you receive:

    • getViewProps: Props to be spread onto a container View.
    • getImageProps: Props to be spread onto the Image component.
    • loading: Boolean indicating if the image is currently loading.
    • error: Error object or string if the image failed to load.
    • retry: A function to attempt reloading the image.

    Example for a basic remote image:

    import React from "react";
    import { Image, View } from "react-native";
    import { ResponsiveImageView } from "react-native-responsive-image-view";
    
    const MyComponent = ({ imageUri }) => (
      <ResponsiveImageView source={{ uri: imageUri }}>
        {({ getViewProps, getImageProps }) => (
          <View {...getViewProps()}>
            <Image {...getImageProps()} />
          </View>
        )}
      </ResponsiveImageView>
    );
  8. Use success and failure callbacks in useResponsiveImageView

    main

    You can provide onLoad and onError callbacks within the configuration object passed to useResponsiveImageView to react to image loading events.

    • onLoad: Called when the image successfully loads.
    • onError: Called when an error occurs during loading, receiving the error as an argument.
    import React from "react";
    import { Image, Text, View } from "react-native";
    import { useResponsiveImageView } from "react-native-responsive-image-view";
    
    const MyComponentWithCallbacks = ({ imageUri }) => {
      const onLoad = React.useCallback(() => {
        console.log("Image has been loaded.");
      }, []);
    
      const onError = React.useCallback((err) => {
        console.error(err);
      }, []);
    
      const { getViewProps, getImageProps } = useResponsiveImageView({
        onLoad,
        onError,
        source: { uri: imageUri },
      });
    
      return (
        <View {...getViewProps()}>
          <Image {...getImageProps()} />
        </View>
      );
    };
  9. Handle loading and error states with useResponsiveImageView

    main

    The useResponsiveImageView hook exposes loading, error, and retry properties to manage the image lifecycle.

    • loading: A boolean indicating if the image is currently loading.
    • error: Contains error information if the image fails to load.
    • retry: A function that can be called to attempt reloading the image.

    You can use these to conditionally render loading indicators or error UI components.

    import { ActivityIndicator, Image, Text, Button, View } from "react-native";
    import { useResponsiveImageView } from "react-native-responsive-image-view";
    
    const MyComponent = ({ imageUri }) => {
      const { error, loading, retry, getViewProps, getImageProps } =
        useResponsiveImageView({
          source: { uri: imageUri },
        });
    
      if (loading) {
        return <ActivityIndicator animating={true} size="large" />;
      }
    
      if (error) {
        return (
          <View>
            <Text>{error}</Text>
            <Button onPress={retry} title="Retry" />
          </View>
        );
      }
    
      return (
        <View {...getViewProps()}>
          <Image {...getImageProps()} />
        </View>
      );
    };
  10. Use the useResponsiveImageView hook

    main

    The useResponsiveImageView hook provides the necessary props to render a responsive image using standard React Native View and Image components. It returns an object containing getViewProps and getImageProps to manage the container and the image itself, along with state properties for loading and error handling.

    To use it, pass a configuration object containing a source (either a URI object or a local resource) to the hook. You then spread the returned props onto your components.

    import React from "react";
    import { Image, View } from "react-native";
    import { useResponsiveImageView } from "react-native-responsive-image-view";
    
    const MyComponent = ({ imageUri }) => {
      const { getViewProps, getImageProps } = useResponsiveImageView({
        source: { uri: imageUri },
      });
    
      return (
        <View {...getViewProps()}>
          <Image {...getImageProps()} />
        </View>
      );
    };
  11. Configure inputs for ResponsiveImageView and useResponsiveImageView

    main

    Both the component and the hook accept the following inputs:

    Basic Inputs

    • source (required): The image source. Can be a local resource (via require or import) or an object with a uri key.
    • onLoad (optional): A function called after the image has loaded and the aspect ratio is calculated.
    • onError (optional): A function called if the image fails to load. Receives an error string.

    Advanced Inputs

    • aspectRatio (optional): A number representing a fixed aspect ratio. If not provided, the library automatically calculates it from the image dimensions. Use this when you need to fit the image into a specific container shape (e.g., a navigation header).