Install
Run the following commands in the React project directory:
pnpm:
pnpm i react-photo-viewyarn:
yarn add react-photo-viewor with npm:
npm install react-photo-viewQuick start
Import the CSS file at the entry point of the application
import 'react-photo-view/dist/react-photo-view.css';Introduce PhotoProvider and PhotoView components where they need to be used, basic usage:
import { PhotoProvider, PhotoView } from 'react-photo-view';
export default function MyComponent() {
return (
<PhotoProvider>
<div className="foo">
{images.map((item, index) => (
<PhotoView key={index} src={item}>
<img src={item} alt="" />
</PhotoView>
))}
</div>
</PhotoProvider>
);
}With the PhotoProvider as the boundary, all the PhotoView images in it will be extracted as a set of image preview galleries in the running order. When an <img > is clicked, it will locate the specified image and open the preview:



If you need the images of the entire page to form a group for preview, you can nest PhotoProvider at the entrance of the page.
Note: react-photo-view only keeps three images loaded in the DOM at a time, since each image is a compositing
layer, which consumes quite a bit of memory.
Animation
Transition effect
react-photo-view uses quite a lot of CSS3 animations to ensure a smoother experience, and uses spring animations to stay close to the native scrolling effect when scrolling. CSS3 animations have a default duration of 400ms, using the cubic-bezier(0.25, 0.8, 0.25, 1) animation function.
You can customize the animation time or function by setting speed , easing:
<PhotoProvider
speed={() => 800}
easing={(type) => (type === 2 ? 'cubic-bezier(0.36, 0, 0.66, -0.56)' : 'cubic-bezier(0.34, 1.56, 0.64, 1)')}
/>speed and easing are functions. The type of the current animation can be judged by the parameter type. The values of type are:
1- open2- closing3- toggleindex

img node, an additional opacity fade effect will be added.Crop Thumbnails
The <PhotoView> component automatically recognizes the child node type, and if the child node is <img >, and the object-fit property is set using CSS, it will have a cropping effect in the zoom animation:
<PhotoView src={imageURL}>
<img src={imageURL} style={{ objectFit: 'cover' }} alt="" />
</PhotoView>
Custom toolbar
Add parameter toolbarRender function to <PhotoProvider>, which must return a ReactNode node.
Zoom in or zoom out
Add a scale control to achieve zoom in and out buttons:
<PhotoProvider
toolbarRender={({ onScale, scale }) => {
return (
<>
<svg className="PhotoView-Slider__toolbarIcon" onClick={() => onScale(scale + 1)} />
<svg className="PhotoView-Slider__toolbarIcon" onClick={() => onScale(scale - 1)} />
</>
);
}}
/>Rotate
react-photo-view does not have a built-in rotation control button by default, but provides a rotation API. We can achieve the rotation effect by simply adding an SVG image:
<PhotoProvider
toolbarRender={({ rotate, onRotate }) => {
return <svg className="PhotoView-Slider__toolbarIcon" onClick={() => onRotate(rotate + 90)} />;
}}
/>The parameters provided by the toolbarRender function are:
images- list of imagesDataType[]index- the current indexnumberonIndexChange- index change callback(index: number) => voidvisible- whether to seebooleanonClose- close event callback() => voidoverlayVisible- whether the overlay is visiblebooleanoverlay- Overlayrotate- the current rotation anglenumberonRotate- Rotate event callback(rotate: number) => voidscale- the current scalenumberonScale- Scale event callback(scale: number) => void
The following example implements a rotating full-screen zoom in and out toolbar:






Long image mode
When loading images whose aspect ratio exceeds 3 times, the mobile device will enter the long image mode by default. That is, the preview starts at the top of the image, and the width of the image fills the width with the mobile device:

Trigger node
<PhotoView> child components can be of the regular React.HTMLAttributes type, such as <img>, <div>, etc.
If it is a custom component, you need to ensure that onClick event can be triggered normally, and forward ref to HTMLElement to ensure the correctness of opening and closing the animation source.
<PhotoView src={imageURL}>
<Button primary>Click</Button>
</PhotoView>PhotoSlider
In general, using <PhotoProvider> in combination with <PhotoView> already suffices for most needs. For more advanced custom controls, <PhotoSlider> can be used.
The parameters of <PhotoSlider> are inherited from <PhotoProvider>. Several additional APIs are exposed:
imageslist of images,DataType[]visiblewhether the controlled propertybooleanis visibleonCloseclose event callback() => voidafterClosecallback after closing animation() => voidindexThe current index controlled propertynumberonIndexChangeindex change callback(index: number) => void
visible is controlled with onClose, and index is controlled with onIndexChange.
export default function MyComponent() {
const [visible, setVisible] = useState(false);
const [index, setIndex] = useState(0);
return (
<>
<Button onClick={() => setIndex(2)}>setIndex(2)</Button>
<Button onClick={() => setIndex(4)}>setIndex(4)</Button>
<Button onClick={() => setVisible(true)} primary>
Click
</Button>
<PhotoSlider
images={images.map((item) => ({ src: item, key: item }))}
visible={visible}
onClose={() => setVisible(false)}
index={index}
onIndexChange={setIndex}
/>
</>
);
}Preview more
<PhotoView > can also be added to the preview queue without subcomponents, but it cannot directly trigger the preview of the current picture. Through this feature, we can realize the function of previewing more pictures through an entrance:
<PhotoProvider>
{images.map((item, index) => (
<PhotoView key={index} src={item}>
{index < 2 ? <img src={item} alt="" /> : undefined}
</PhotoView>
))}
</PhotoProvider>

Custom render node
<PhotoView> has built-in support for image preview by default, just pass src, the component will automatically recognize the width and height of the image.
We can also implement the preview of custom nodes through the render function to support the needs of video or pdf.
const elementSize = 400;
function MyComponent() {
return (
<PhotoView
width={elementSize}
height={elementSize}
render={({ scale, attrs }) => {
const width = parseFloat((attrs?.style?.width ?? 0) as string);
const offset = (width - elementSize) / elementSize;
const childScale = scale === 1 ? scale + offset : 1 + offset;
return (
<div {...attrs}>
<div style={{ transform: `scale(${childScale})`, width: elementSize, transformOrigin: '0 0' }}>
<div>Hello world</div>
<Button>button</Button>
<input onMouseDown={(e) => e.stopPropagation()} />
</div>
</div>
);
}}
>
<Button primary>Click</Button>
</PhotoView>
);
}Note: After the gallery is zoomed, it will first be scaled with scale, and after the animation is over, it will be
adjusted to the width and height corresponding to the current scale, and the scale will be reset to 1.
PhotoProvider parameter
Custom description
Add the overlayRender function to <PhotoProvider> to implement custom nodes. The return value of the function parameter is the same as that of toolbarRender.






Loop preview
Add parameter loop on <PhotoProvider> to change the number of loop previews. Set to boolean to enable and disable, set to number type to exceed the specific number to enable loop preview, the default value is 3 sheets:
<PhotoProvider loop={4} />


Mask Transparency
The default is opaque, and the transparency will gradually decrease during the pull-up process. You can add maskOpacity to <PhotoProvider> to adjust the default transparency, which can be set to a number between 0-1:
<PhotoProvider maskOpacity={0.5} />
Don't show top button area
Set bannerVisible to false to hide the top area:
<PhotoProvider bannerVisible={false} />
Masking event
pullClosable (default true) can close the gallery by pulling down, maskClosable (default true) can click on the mask to close the gallery:
<PhotoProvider pullClosable={false} maskClosable={false} />
Custom feedback
<PhotoView> If loading fails, empty nodes are rendered by default, and you may need to set your own error feedback nodes according to the current UI.
brokenElement- set the load failure patternReact.ReactElementloadingElement- set the loading patternReact.ReactElement