fix(component): image preview fallback (#3058)

This commit is contained in:
Alex Yang
2023-07-06 09:22:23 +00:00
committed by GitHub
parent f468dff6aa
commit ce63364299
@@ -16,10 +16,13 @@ import {
} from '@blocksuite/icons'; } from '@blocksuite/icons';
import type { Workspace } from '@blocksuite/store'; import type { Workspace } from '@blocksuite/store';
import clsx from 'clsx'; import clsx from 'clsx';
import { useErrorBoundary } from 'foxact/use-error-boundary';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import type { ReactElement } from 'react'; import type { PropsWithChildren, ReactElement } from 'react';
import { Suspense, useCallback } from 'react'; import { Suspense, useCallback } from 'react';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import type { FallbackProps } from 'react-error-boundary';
import { ErrorBoundary } from 'react-error-boundary';
import useSWR from 'swr'; import useSWR from 'swr';
import { useZoomControls } from './hooks/use-zoom'; import { useZoomControls } from './hooks/use-zoom';
@@ -252,7 +255,9 @@ const ImagePreviewModalImpl = (
assertExists(block); assertExists(block);
setCaption(block?.caption); setCaption(block?.caption);
}, [props.blockId, props.pageId, props.workspace]); }, [props.blockId, props.pageId, props.workspace]);
const { data } = useSWR(['workspace', 'image', props.pageId, props.blockId], { const { data, error } = useSWR(
['workspace', 'image', props.pageId, props.blockId],
{
fetcher: ([_, __, pageId, blockId]) => { fetcher: ([_, __, pageId, blockId]) => {
const page = props.workspace.getPage(pageId); const page = props.workspace.getPage(pageId);
assertExists(page); assertExists(page);
@@ -261,12 +266,17 @@ const ImagePreviewModalImpl = (
return props.workspace.blobs.get(block?.sourceId); return props.workspace.blobs.get(block?.sourceId);
}, },
suspense: true, suspense: true,
}); }
);
useErrorBoundary(error);
const [prevData, setPrevData] = useState<string | null>(() => data); const [prevData, setPrevData] = useState<string | null>(() => data);
const [url, setUrl] = useState<string | null>(null); const [url, setUrl] = useState<string | null>(null);
if (prevData !== data) { if (data === null) {
return null;
} else if (prevData !== data) {
if (url) { if (url) {
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
} }
@@ -461,6 +471,21 @@ const ImagePreviewModalImpl = (
); );
}; };
const ErrorLogger = (props: FallbackProps) => {
useEffect(() => {
console.error('image preview modal error', props.error);
}, [props.error]);
return null;
};
export const ImagePreviewErrorBoundary = (
props: PropsWithChildren
): ReactElement => {
return (
<ErrorBoundary fallbackRender={ErrorLogger}>{props.children}</ErrorBoundary>
);
};
export const ImagePreviewModal = ( export const ImagePreviewModal = (
props: ImagePreviewModalProps props: ImagePreviewModalProps
): ReactElement | null => { ): ReactElement | null => {
@@ -530,11 +555,14 @@ export const ImagePreviewModal = (
} }
return ( return (
<ImagePreviewErrorBoundary>
<div <div
data-testid="image-preview-modal" data-testid="image-preview-modal"
className={`${imagePreviewBackgroundStyle} ${isOpen ? loaded : unloaded}`} className={`${imagePreviewBackgroundStyle} ${
isOpen ? loaded : unloaded
}`}
> >
<Suspense fallback={<div />}> <Suspense>
<ImagePreviewModalImpl <ImagePreviewModalImpl
{...props} {...props}
blockId={blockId} blockId={blockId}
@@ -564,5 +592,6 @@ export const ImagePreviewModal = (
</svg> </svg>
</button> </button>
</div> </div>
</ImagePreviewErrorBoundary>
); );
}; };