React Image is an <img>
tag
replacement and hook for React.js, supporting
fallback to alternate sources when loading an image fails.
React Image allows one or more images to be used as
fallback images in the event that the browser couldn’t load the previous
image. When using the component, you can specify any React element to be
used before an image is loaded (i.e. a spinner) or in the event that the
specified image(s) could not be loaded. When using the hook this can be
achieved by wrapping the component with <Suspense>
and specifying the fallback
prop.
React Image uses the useImage
hook
internally which encapsulates all the image loading logic. This hook
works with React Suspense by default and will suspend painting until the
image is downloaded and decoded by the browser.
react-image
using npm:npm install react-image --save
<script src="https://unpkg.com/react-image/umd/index.js"></script>
react-image
has no external dependencies, aside for a
version of react
and react-dom
which support
hooks and @babel/runtime
.
You can use the standalone component, documented below, or the
useImage
hook.
The useImage
hook allows for incorperating
react-image
’s logic in any component. When using the hook,
the component can be wrapped in <Suspense>
to keep it
from rendering until the image is ready. Specify the
fallback
prop to show a spinner or any other component to
the user while the browser is loading. The hook will throw an error if
it failes to find any images. You can wrap your componenet with an Error
Boundry to catch this scenario and do/show something.
Example usage:
import React, {Suspense} from 'react'
import {useImage} from 'react-image'
function MyImageComponent() {
const {src} = useImage({
srcList: 'https://www.example.com/foo.jpg',
})
return <img src={src} />
}
export default function MyComponent() {
return (
<Suspense>
<MyImageComponent />
</Suspense>
) }
useImage
API:srcList
: a string or array of strings.
useImage
will try loading these one at a time and returns
after the first one is successfully loaded
imgPromise
: a promise that accepts a url and returns
a promise which resolves if the image is successfully loaded or rejects
if the image doesn’t load. You can inject an alternative implementation
for advanced custom behaviour such as logging errors or dealing with
servers that return an image with a 404 header
useSuspense
: boolean. By default,
useImage
will tell React to suspend rendering until an
image is downloaded. Suspense can be disabled by setting this to
false.
returns:
src
: the resolved image addressisLoading
: the currently loading status. Note: this is
never true when using Suspenseerror
: any errors ecountered, if anyWhen possible, you should use the useImage
hook. This
provides for greater flexability and provides support for React
Suspense.
Include react-image
in your component:
import {Img} from 'react-image'
and set a source for the image:
const myComponent = () => <Img src="https://www.example.com/foo.jpg" />
will resolve to:
<img src="https://www.example.com/foo.jpg">
If the image cannot be loaded, <img>
will
not be rendered, preventing a “broken” image from showing.
When src
is specified as an array,
react-image
will attempt to load all the images specified
in the array, starting at the first and continuing until an image has
been successfully loaded.
const myComponent = () => (
<Img
={['https://www.example.com/foo.jpg', 'https://www.example.com/bar.jpg']}
src/>
)
If an image has previously been attempted unsuccessfully,
react-image
will not retry loading it again until the page
is reloaded.
const myComponent = () => (
<Img
={['https://www.example.com/foo.jpg', 'https://www.example.com/bar.jpg']}
src={/*any valid react element */}
loader/>
)
If an image was previously loaded successfully (since the last time the page was loaded), the loader will not be shown and the image will be rendered immediately instead.
const myComponent = () => (
<Img
={['https://www.example.com/foo.jpg', 'https://www.example.com/bar.jpg']}
src={/*any valid react element */}
unloader/>
)
The following options only apply to the <Img>
component, not to the useImage
hook. When using the hook
you can inject a custom image resolver with custom behaviour as
required.
By default and when supported by the browser,
react-image
uses Image.decode()
to decode the image and only render it when it’s fully ready to be
painted. While this doesn’t matter much for vector images (such as
svg’s) which are rendered immediately, decoding the image before
painting prevents the browser from hanging or flashing while the image
is decoded. If this behaviour is undesirable, it can be disabled by
setting the decode
prop to false
:
const myComponent = () => (
<Img src={'https://www.example.com/foo.jpg'} decode={false} />
)
When loading images from another domain with a CORS
policy, you may find you need to use the crossorigin
attribute. For example:
const myComponent = () => (
<Img src={'https://www.example.com/foo.jpg'} crossorigin="anonymous" />
)
A wrapper element container
can be used to facilitate
higher level operations which are beyond the scope of this project.
container
takes a single property, children
which is whatever is passed in by React Image (i.e. the
final <img>
or the loaders).
For example, to animate the display of the image (and animate out the loader) a wrapper can be set:
<Img
={'https://www.example.com/foo.jpg'}
src={(children) => {
containerreturn <div className="foo">{children}</div>
}}/>
The <img>
will now be contained by the
div
with class foo
which can be targeted via
css. A crude example of a transition using ReactCSSTransitionReplace
can be found
here. Error reporting (i.e. logging images that loaded ok or failed
to load) can be accomplished with container
, too. A sample
implementation can be found
here.
By default, the loader and unloader components will also be wrapped
by the container
component. These can be set independently
by passing a container via loaderContainer
or
unloaderContainer
. To disable the loader or unloader from
being wrapped, pass a noop to loaderContainer
or
unloaderContainer
(like
unloaderContainer={img => img}
).
By definition, React Image will try loading images
right away. This may be undesirable in some situations, such as when the
page has many images. As with any react element, rendering can be
delayed until the image is actually visible in the viewport using
popular libraries such as react-visibility-sensor
.
Here is a quick sample (psudocode/untested!):
import {Img} from 'react-image'
import VisibilitySensor from 'react-visibility-sensor'
const myComponent = () =>
<VisibilitySensor>
<Img src='https://www.example.com/foo.jpg'>
</VisibilitySensor>
Note: it is not nesesary to use React Image to
prevent loading of images past “the fold” (i.e. not currently visable on
in the window). Instead just use the native HTML
<img>
element and the loading="lazy"
prop. See more here.
see above
react-image
is available under the MIT License