Skip to content

Commit

Permalink
refactor: Modal을 context로 관리 #272
Browse files Browse the repository at this point in the history
  • Loading branch information
rbgksqkr committed Sep 20, 2024
1 parent af686cd commit f23bc37
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 4 deletions.
9 changes: 6 additions & 3 deletions frontend/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ReactDOM from 'react-dom/client';
import { RecoilRoot } from 'recoil';

import App from './App';
import ModalProvider from './providers/ModalProvider/ModalProvider';
import ToastProvider from './providers/ToastProvider/ToastProvider';
import GlobalStyle from './styles/GlobalStyle';
import { Theme } from './styles/Theme';
Expand Down Expand Up @@ -34,9 +35,11 @@ enableMocking().then(() => {
<RecoilRoot>
<ThemeProvider theme={Theme}>
<Global styles={GlobalStyle} />
<ToastProvider>
<App />
</ToastProvider>
<ModalProvider>
<ToastProvider>
<App />
</ToastProvider>
</ModalProvider>
<ReactQueryDevtools initialIsOpen={false} />
</ThemeProvider>
</RecoilRoot>
Expand Down
60 changes: 60 additions & 0 deletions frontend/src/providers/ModalProvider/ModalProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { createContext, PropsWithChildren, useMemo, useState } from 'react';

interface ModalContent {
title: string;
message: string;
}

interface ModalState extends ModalContent {
isOpen: boolean;
onClose: () => void;
}

interface Modal extends ModalContent {
Component: React.FC<ModalState> | null;
isOpen: boolean;
}

interface ModalDispatchContextProps {
show: (Component: React.FC<ModalState> | null, { title, message }: ModalContent) => void;
close: () => void;
}

export const ModalDispatchContext = createContext<ModalDispatchContextProps | null>(null);

const ModalProvider = ({ children }: PropsWithChildren) => {
const [modal, setModal] = useState<Modal>({
Component: null,
isOpen: false,
title: '',
message: '',
});

const show = (Component: React.FC<ModalState> | null, { title, message }: ModalContent) => {
setModal({
Component,
title,
message,
isOpen: true,
});
};

const close = () => {
setModal((prev) => ({
...prev,
Component: null,
isOpen: false,
}));
};

const dispatch = useMemo(() => ({ show, close }), []);

return (
<ModalDispatchContext.Provider value={dispatch}>
{children}
{modal.isOpen && modal.Component && <modal.Component onClose={close} {...modal} />}
</ModalDispatchContext.Provider>
);
};

export default ModalProvider;
5 changes: 4 additions & 1 deletion frontend/src/utils/test-utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { MutableSnapshot } from 'recoil';
import AsyncErrorBoundary from '@/components/common/ErrorBoundary/AsyncErrorBoundary';
import RootErrorBoundary from '@/components/common/ErrorBoundary/RootErrorBoundary';
import Spinner from '@/components/common/Spinner/Spinner';
import ModalProvider from '@/providers/ModalProvider/ModalProvider';
import ToastProvider from '@/providers/ToastProvider/ToastProvider';
import GlobalStyle from '@/styles/GlobalStyle';
import { Theme } from '@/styles/Theme';
Expand Down Expand Up @@ -38,7 +39,9 @@ const wrapper = ({
<RootErrorBoundary>
<AsyncErrorBoundary pendingFallback={pendingFallback}>
<Global styles={GlobalStyle} />
<ToastProvider>{children}</ToastProvider>
<ModalProvider>
<ToastProvider>{children}</ToastProvider>
</ModalProvider>
</AsyncErrorBoundary>
</RootErrorBoundary>
</MemoryRouter>
Expand Down

0 comments on commit f23bc37

Please sign in to comment.