Global Loader 표시에 관한 내용입니다
해당 기능은 공통업무 기능입니다. 다음과 같이 미리 준비된 Boilerplate confy-app 형태로 제공됩니다.
/src/shared/provider/LoadingProvider.ts
import { LoadingContext } from '@/shared/hooks/useLoading'
import { Box, Portal, Spinner, Theme } from '@confy-ui/react/themes'
import { useIsFetching, useIsMutating } from '@tanstack/react-query'
import React, { useMemo, useRef, useState } from 'react'
interface LoadingProviderProps {
children: React.ReactNode
disableGlobalAPILoading?: boolean
}
export const LoadingProvider = ({
children,
disableGlobalAPILoading = false
}: LoadingProviderProps) => {
const [isLoading, setIsLoading] = useState(false)
const loadingCountRef = useRef(0)
const isFetching = useIsFetching({
predicate: (query) => (query.meta?.showLoading as boolean) ?? true
})
const isMutating = useIsMutating({
predicate: (mutation) => (mutation.meta?.showLoading as boolean) ?? true
})
const isLoadingAPI = useMemo(() => {
if (disableGlobalAPILoading) return false
return isFetching > 0 || isMutating > 0
}, [disableGlobalAPILoading, isFetching, isMutating])
const show = () => {
loadingCountRef.current += 1
if (loadingCountRef.current === 1) {
setIsLoading(true)
}
}
const hide = () => {
if (loadingCountRef.current > 0) {
loadingCountRef.current -= 1
if (loadingCountRef.current === 0) {
setIsLoading(false)
}
}
}
return (
<LoadingContext.Provider value={{ isLoading, show, hide }}>
{children}
{(isLoading || isLoadingAPI) && (
<Portal asChild>
<Theme>
<Box
as='div'
className='loading-overlay'
style={{
width: '100vw',
height: '100vh',
background: '#00000080',
position: 'fixed',
top: 0,
left: 0,
zIndex: 9999,
justifyContent: 'center',
alignItems: 'center]'
}}
>
<Spinner size={'3'} />
</Box>
</Theme>
</Portal>
)}
</LoadingContext.Provider>
)
}
Global Context를 통해 Loading 표시를 관리 합니다useLoading 을통해 Loading 표시를 제어 합니다import { useDialog } from '@/shared/hooks/useDialog'
import { Button } from '@confy-ui/react/themes'
export default function Page2() {
const { show, hide } = useLoading()
const onClickButton = (data: { name: string; email: string }) => {
show() // Global Loading 표시
hide() // Global Loading 숨김
}
return (
<Button onClick={onClickButton}>show dialog</Button>
)
}
useLoading을 통해서 받은 show, hide 함수를 통해 Global Loading 제어가 가능합니다disableGlobalAPILoading 옵션을 통해 API 호출 시 로딩창을 표시 여부를 제어 할 수 있습니다
/src/main.ts
const initializeApp = async () => {
console.log(
'%c' + 'Confy InitializeApp!',
'color: #7289DA; -webkit-text-stroke: 2px black; font-size: 72px; font-weight: bold;'
)
console.debug('console.debug initializeApp')
const i18n = await i18nInstance()
root.render(
<StrictMode>
<I18nextProvider i18n={i18n}>
<ThemeProviders>
<DialogProvider>
<CustomQueryProvider>
<LoadingProvider disableGlobalAPILoading={true}>
<InitializeProvider>
<VersionCheckProvider>
<DefaultRouterProvider />
</VersionCheckProvider>
</InitializeProvider>
</LoadingProvider>
</CustomQueryProvider>
</DialogProvider>
</ThemeProviders>
</I18nextProvider>
</StrictMode>
)
}
LoadingProvider의 Portal의 컴포넌트를 수정 하면 됩니다
/src/shared/provider/LoadingProvider.ts
export const LoadingProvider = ({
children,
disableGlobalAPILoading = false
}: LoadingProviderProps) => {
return (
<LoadingContext.Provider value={{ isLoading, show, hide }}>
{children}
{(isLoading || isLoadingAPI) && (
<Portal asChild>
<Theme>
<Box
as='div'
className='loading-overlay'
style={{
width: '100vw',
height: '100vh',
background: '#00000080',
position: 'fixed',
top: 0,
left: 0,
zIndex: 9999,
justifyContent: 'center',
alignItems: 'center]'
}}
>
<Spinner size={'3'} />
</Box>
</Theme>
</Portal>
)}
</LoadingContext.Provider>
)
}