코딩 정보/React
[React] 재활용성이 좋은 modal 만들기
꽁이꽁설꽁돌
2024. 8. 10. 12:56
728x90
반응형
목차
범용성이 좋은 modal component
import { useEffect, useRef } from "react";
import { createPortal } from "react-dom";
function Modal({ children, className = "", open, onClose }) {
const dialog = useRef();
useEffect(() => {
//참조값을 지정해 놓기
const modal = dialog.current;
if (open) {
modal.showModal();
}
return () => {
modal.close();
};
}, [open]);
return createPortal(
<dialog ref={dialog} className={`modal ${className}`} onClose={onClose}>
{children}
</dialog>,
document.getElementById("modal")
);
}
export default Modal;
컴포넌트 설명
- children과 className을 통해 css 및 컴포넌트의 활용성을 높였다.
- open이라는 상태를 전달함으로써 모달이 닫히고 열리는 것을 구현하였고 clear함수를 통해 닫히는 기능이 만들어지는 것을 가져가면 좋을 것 같다.
- createPortal을 이용해서 dom의 modal에 직접 연결해 주었다.
- onClose를 쓴 이유는 esc를 누르면 외부에서 modal은 닫히지만 state자체는 변경되지 않았기 때문에 다시 모달이 안열리는 경우를 막기 위해서이다.
modal ContextProvider
아래 코드는 이러한 모달을 이용한 컴포넌트들을 전역적으로 관리하기 위해 만든 contextProvider이다.
import { createContext, useState } from "react";
export const userProgressContext = createContext({
progress: "",
showCart: () => {},
hideCart: () => {},
showCheckout: () => {},
hideCheckout: () => {},
});
export function UserProgressContextProvider({ children }) {
const [userProgress, setUserProgress] = useState("");
function showCart() {
setUserProgress("cart");
}
function hideCart() {
setUserProgress("");
}
function showCheckout() {
setUserProgress("checkout");
}
function hideCheckout() {
setUserProgress("");
}
const userProgressCtx = {
progress: userProgress,
showCart,
hideCart,
showCheckout,
hideCheckout,
};
return (
<userProgressContext.Provider value={userProgressCtx}>
{children}
</userProgressContext.Provider>
);
}
전역적으로 설정한 모달 컴포넌트의 활용
import { useContext } from "react";
import Button from "./UI/Button";
import { userProgressContext } from "./store/UserProgressContext";
import Modal from "./Modal";
import CartItem from "./CartItem";
function Cart() {
const userProgressCtx = useContext(userProgressContext);
function handleHideCart() {
userProgressCtx.hideCart();
}
return (
<Modal
className="cart"
open={userProgressCtx.progress === "cart"}
onClose={userProgressCtx.progress === "cart" ? handleHideCart : null}
>
<Button onClick={handleCheckout}>go to Checkout</Button>
</Modal>
);
}
export default Cart;
위 코드에서의 주의사항이다.
onClose={userProgressCtx.progress === "cart" ? handleHideCart : null}
이렇게 코드를 짠 이유는 userProgressCtx.progress가 checkout일 때는 onClose의 기능을 비활성화해서 checkout이 열리게끔 만들어야하기 때문이다.
반응형