mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
fix(use-image): load images after props change (#4523)
* fix(use-image): load image after props change * chore(changeset): add changeset * refactor(use-image): remove unused props * feat(use-image): add test case * fix(use-image): apply useCallback to load & remove status check * chore(changeset): update package name
This commit is contained in:
parent
8452603b5b
commit
f9c2be4509
5
.changeset/light-peaches-reflect.md
Normal file
5
.changeset/light-peaches-reflect.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"@heroui/use-image": patch
|
||||
---
|
||||
|
||||
fix loading image after props changes (#4518)
|
||||
@ -27,6 +27,19 @@ describe("use-image hook", () => {
|
||||
await waitFor(() => expect(result.current).toBe("loaded"));
|
||||
});
|
||||
|
||||
it("can handle changing image", async () => {
|
||||
const {result, rerender} = renderHook(() => useImage({src: undefined}));
|
||||
|
||||
expect(result.current).toEqual("pending");
|
||||
|
||||
setTimeout(() => {
|
||||
rerender({src: "/test.png"});
|
||||
}, 3000);
|
||||
|
||||
mockImage.simulate("loaded");
|
||||
await waitFor(() => expect(result.current).toBe("loaded"));
|
||||
});
|
||||
|
||||
it("can handle error image", async () => {
|
||||
mockImage.simulate("error");
|
||||
const {result} = renderHook(() => useImage({src: "/test.png"}));
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
import type {ImgHTMLAttributes, SyntheticEvent} from "react";
|
||||
|
||||
import {useRef, useState, useEffect, MutableRefObject} from "react";
|
||||
import {useRef, useState, useEffect, useCallback} from "react";
|
||||
import {useIsHydrated} from "@heroui/react-utils";
|
||||
import {useSafeLayoutEffect} from "@heroui/use-safe-layout-effect";
|
||||
|
||||
@ -66,7 +66,7 @@ type ImageEvent = SyntheticEvent<HTMLImageElement, Event>;
|
||||
*/
|
||||
|
||||
export function useImage(props: UseImageProps = {}) {
|
||||
const {onLoad, onError, ignoreFallback} = props;
|
||||
const {onLoad, onError, ignoreFallback, src, crossOrigin, srcSet, sizes, loading} = props;
|
||||
|
||||
const isHydrated = useIsHydrated();
|
||||
|
||||
@ -96,11 +96,31 @@ export function useImage(props: UseImageProps = {}) {
|
||||
}
|
||||
};
|
||||
|
||||
const load = useCallback((): Status => {
|
||||
if (!src) return "pending";
|
||||
if (ignoreFallback) return "loaded";
|
||||
|
||||
const img = new Image();
|
||||
|
||||
img.src = src;
|
||||
if (crossOrigin) img.crossOrigin = crossOrigin;
|
||||
if (srcSet) img.srcset = srcSet;
|
||||
if (sizes) img.sizes = sizes;
|
||||
if (loading) img.loading = loading;
|
||||
|
||||
imageRef.current = img;
|
||||
if (img.complete && img.naturalWidth) {
|
||||
return "loaded";
|
||||
}
|
||||
|
||||
return "loading";
|
||||
}, [src, crossOrigin, srcSet, sizes, onLoad, onError, loading]);
|
||||
|
||||
useSafeLayoutEffect(() => {
|
||||
if (isHydrated) {
|
||||
setStatus(setImageAndGetInitialStatus(props, imageRef));
|
||||
setStatus(load());
|
||||
}
|
||||
}, [isHydrated]);
|
||||
}, [isHydrated, load]);
|
||||
|
||||
/**
|
||||
* If user opts out of the fallback/placeholder
|
||||
@ -109,31 +129,6 @@ export function useImage(props: UseImageProps = {}) {
|
||||
return ignoreFallback ? "loaded" : status;
|
||||
}
|
||||
|
||||
function setImageAndGetInitialStatus(
|
||||
props: UseImageProps,
|
||||
imageRef: MutableRefObject<HTMLImageElement | null | undefined>,
|
||||
): Status {
|
||||
const {loading, src, srcSet, crossOrigin, sizes, ignoreFallback} = props;
|
||||
|
||||
if (!src) return "pending";
|
||||
if (ignoreFallback) return "loaded";
|
||||
|
||||
const img = new Image();
|
||||
|
||||
img.src = src;
|
||||
if (crossOrigin) img.crossOrigin = crossOrigin;
|
||||
if (srcSet) img.srcset = srcSet;
|
||||
if (sizes) img.sizes = sizes;
|
||||
if (loading) img.loading = loading;
|
||||
|
||||
imageRef.current = img;
|
||||
if (img.complete && img.naturalWidth) {
|
||||
return "loaded";
|
||||
}
|
||||
|
||||
return "loading";
|
||||
}
|
||||
|
||||
export const shouldShowFallbackImage = (status: Status, fallbackStrategy: FallbackStrategy) =>
|
||||
(status !== "loaded" && fallbackStrategy === "beforeLoadOrError") ||
|
||||
(status === "failed" && fallbackStrategy === "onError");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user