π΄ Introduction
βͺ μ΄λ μμΉμμλ μ¬μ©ν μ μλ λͺ¨λ¬μ°½μ λ§λλ ꡬ쑰
π Usage
π public/index.html
<!-- ··· -->
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="modal"></div>
</body>
<!-- ··· -->
π index.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import { Provider } from "react-redux";
import store from "./store";
import App from "./App";
import Modal from "./Modal";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<>
<Provider store={store}>
<Modal />
<App />
</Provider>
</>
);
π store.js
import { configureStore } from "@reduxjs/toolkit";
import logger from "redux-logger";
import modalReducer from "./modalSlice";
import ReduxThunk from "redux-thunk";
const store = configureStore({
reducer: {
modal: modalReducer,
},
middleware: (getDefaultMiddleware) => [
...getDefaultMiddleware({ serializableCheck: false }),
logger,
ReduxThunk,
],
});
export default store;
π modalSlice.js
import { createSlice } from "@reduxjs/toolkit";
export const ModalSlice = createSlice({
name: "modal",
initialState: {
show: false,
type: "",
props: {},
},
reducers: {
setModal: (state, { payload }) => {
state.type = payload.modalType;
state.props = payload.modalProps;
state.show = true;
},
hideModal: (state) => {
state.show = false;
state.type = "";
state.props = {};
},
},
});
export const { setModal, hideModal } = ModalSlice.actions;
export default ModalSlice.reducer;
π Modal.jsx
import { createPortal } from "react-dom";
import GlobalModal from "./GlobalModal";
const element = document.querySelector("#modal");
const Modal = () => {
return createPortal(<GlobalModal />, element);
};
export default Modal;
π GlobalModal.jsx
import React from "react";
import AlertModal from "./AlertModal";
import TimeoutModal from "./TimeoutModal";
import ToastModal from "./ToastModal";
import { useSelector } from "react-redux";
// π μ§μ λ§λ 컀μ€ν
λͺ¨λ¬ μ»΄ν¬λνΈλ₯Ό μ°κ²°μν¨λ€.
export const MODAL_TYPES = {
AlertModal: "alert",
TimeoutModal: "timeout",
ToastModal : "ToastModal",
};
const MODAL_COMPONENTS = {
[MODAL_TYPES.AlertModal]: AlertModal,
[MODAL_TYPES.TimeoutModal]: TimeoutModal,
[MODAL_TYPES.ToastModal]: ToastModal,
};
const GlobalModal = () => {
const { show, type, props } = useSelector((state) => state.modal);
const renderComponent = () => {
if (!show) {
return null;
}
const ModalComponent = MODAL_COMPONENTS[type];
return <ModalComponent {...props} />;
};
return <>{renderComponent()}</>;
};
export default GlobalModal;
π useModal.js
import { useDispatch } from "react-redux";
import { setModal, hideModal } from "./modalSlice";
const useModal = () => {
const dispatch = useDispatch();
const showModal = ({ modalType, modalProps }) => {
dispatch(setModal({ modalType, modalProps }));
};
const closeModal = () => {
dispatch(hideModal());
};
return [ showModal, closeModal ];
};
export default useModal;
π‘ Reference
Usage