Render sandpack when it in view

This commit is contained in:
Defectink
2022-04-14 14:17:19 +08:00
parent 859fd847f1
commit b9049bfe19
3 changed files with 36 additions and 11 deletions

View File

@ -2,25 +2,25 @@ import { FC, useEffect, useState } from 'react';
import { Sandpack, SandpackProps } from '@codesandbox/sandpack-react';
import '@codesandbox/sandpack-react/dist/index.css';
import { useTheme } from 'next-themes';
import useInView from 'lib/hooks/useInView';
interface Props extends SandpackProps {}
const RUASandpack: FC<Props> = ({ ...rest }) => {
const [mounted, setMounted] = useState(false);
const { systemTheme, theme } = useTheme();
const currentTheme = theme === 'system' ? systemTheme : theme;
useEffect(() => setMounted(true), []);
if (!mounted) return null;
const { ref, inView } = useInView();
return (
<>
<div className="my-2">
<Sandpack
{...rest}
theme={currentTheme === 'dark' ? 'dark' : 'light'}
/>
<div className="my-2 min-h-[402px]" ref={ref}>
{inView && (
<Sandpack
{...rest}
theme={currentTheme === 'dark' ? 'dark' : 'light'}
/>
)}
</div>
</>
);

View File

@ -11,7 +11,7 @@ interface Props
const Image = ({ src, alt }: Props) => {
return (
<>
<p className={styles.imageContainer}>
<span className={styles.imageContainer}>
<NextImage
src={src ?? ''}
alt={alt}
@ -19,7 +19,7 @@ const Image = ({ src, alt }: Props) => {
className={styles.image}
/>
{alt && <span className="block text-center text-gray-400">{alt}</span>}
</p>
</span>
</>
);
};

25
lib/hooks/useInView.ts Normal file
View File

@ -0,0 +1,25 @@
import { useEffect, useRef, useState } from 'react';
const useInView = () => {
const ref = useRef(null);
const [inView, setInView] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
if (ref.current) {
setInView(true);
observer.unobserve(ref.current);
}
}
});
});
ref.current && observer.observe(ref.current);
}, []);
return { ref, inView };
};
export default useInView;