Skip to content

Commit

Permalink
fix(image): fix image for not trigger native event the bug (#2616)
Browse files Browse the repository at this point in the history
  • Loading branch information
HaixingOoO authored Nov 30, 2023
1 parent 5897e7b commit f189c37
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 6 deletions.
12 changes: 7 additions & 5 deletions src/avatar/__tests__/avatar.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { vi, render, fireEvent } from '@test/utils';
import { vi, render, simulateImageEvent, mockDelay } from '@test/utils';
import Avatar from '../Avatar';

describe('Avatar 组件测试', () => {
Expand Down Expand Up @@ -29,9 +29,11 @@ describe('Avatar 组件测试', () => {

test('Avatar onError 回调', async () => {
const mockOnErrorFn = vi.fn();
const wrapper = render(<Avatar image="http://error/" alt="test-avatar" onError={mockOnErrorFn}></Avatar>);
const image = wrapper.getByAltText('test-avatar');
fireEvent(image, new Event('error'));
expect(mockOnErrorFn).toHaveBeenCalledTimes(1);
const { container } = render(<Avatar image="http://error/" alt="test-avatar" onError={mockOnErrorFn}></Avatar>);
const imageDom = container.querySelector('img');
simulateImageEvent(imageDom, 'error');
await mockDelay(300);
expect(mockOnErrorFn).toHaveBeenCalled();
expect(mockOnErrorFn.mock.calls[0][0].e.type).toBe('error');
});
});
42 changes: 41 additions & 1 deletion src/image/Image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ import { StyledProps } from '../common';
import useDefaultProps from '../hooks/useDefaultProps';
import useImagePreviewUrl from '../hooks/useImagePreviewUrl';

export function isImageValid(src: string) {
return new Promise((resolve) => {
const img = document.createElement('img');
img.onerror = () => resolve(false);
img.onload = () => resolve(true);
img.src = src;
});
}

export type ImageProps = TdImageProps &
StyledProps & {
onClick?: (e: MouseEvent<HTMLDivElement>) => void;
Expand Down Expand Up @@ -93,7 +102,11 @@ const InternalImage: React.ForwardRefRenderFunction<HTMLDivElement, ImageProps>
}, [lazy, imageRef]);

const [hasError, setHasError] = useState(false);

// 判断是否执行过onError事件,要不在CSR模式下会执行两次onError
const isFirstError = useRef(false);
const handleError = (e: SyntheticEvent<HTMLImageElement>) => {
isFirstError.current = true;
setHasError(true);
if (fallback) {
setImageSrc(fallback);
Expand All @@ -102,13 +115,39 @@ const InternalImage: React.ForwardRefRenderFunction<HTMLDivElement, ImageProps>
onError?.({ e });
};

const imgRef = useRef();
useEffect(() => {
if (hasError && previewUrl) {
setHasError(false);
}
// eslint-disable-next-line
// 在SSR在判断执行onError
previewUrl &&
isImageValid(previewUrl as string).then((isValid) => {
// SSR模式下会执行,CSR模式下不会执行
// 这里添加setTimeout是因为CSR image渲染时,onError有时快有时慢,会导致执行顺序不同导致的bug
setTimeout(() => {
if (!isValid && !isFirstError.current) {
// SSR模式下获取不到imaage的合成事件,暂时传递image实例
handleError(imgRef.current);
}
}, 0);
});

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [previewUrl]);

useEffect(() => {
// SSR下执行
if (imgRef.current) {
const { complete, naturalWidth, naturalHeight } = imgRef.current;
if (complete && naturalWidth !== 0 && naturalHeight !== 0) {
// SSR模式下获取不到imaage的合成事件,暂时传递image实例
handleLoad(imgRef.current);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const hasMouseEvent = overlayTrigger === 'hover';
const [shouldShowOverlay, setShouldShowOverlay] = useState(!hasMouseEvent);
const handleToggleOverlay = (overlay: boolean) => {
Expand Down Expand Up @@ -148,6 +187,7 @@ const InternalImage: React.ForwardRefRenderFunction<HTMLDivElement, ImageProps>
const url = typeof imageSrc === 'string' ? imageSrc : previewUrl;
return (
<img
ref={imgRef}
src={url}
onError={handleError}
onLoad={handleLoad}
Expand Down

0 comments on commit f189c37

Please sign in to comment.