아직 준비중인 기능들이 있어 alert창을 띄우는데 커스텀을 하고싶었고,
여러 화면에서 사용할 것이기 때문에 컴포넌트화해서 사용하고 싶었다.
방법을 찾아본 결과 이 방법이 제일 간단하고 편리한거 같아서 따라하게 되었다.
hooks/useModal.ts
import { useState } from "react";
export function useModal() {
const [isShowing, setIsShowing] = useState(false);
const modalToggle = () => {
setIsShowing(!isShowing);
};
return {
isShowing,
modalToggle,
};
}
- useModal 커스텀 훅을 만들어서 모달이 보이는 상태와 모달 토글 이벤트를 넘겨주었다.
component/Modal
interface IPropsModal {
isShowing: boolean;
hide: () => void;
message: string;
}
export function Modal({ isShowing, hide, message }: IPropsModal) {
return isShowing
? ReactDOM.createPortal(
<Wrap onClick={hide}>
<ModalInner
className="modal"
onClick={(e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
}}
>
<div>
<AlertIcon />
<p>{message}</p>
</div>
<Button onClick={hide}>닫기</Button>
</ModalInner>
</Wrap>,
document.body,
)
: null;
}
ReactDOM.createPortal로 모달창을 document.body에 넣어준다.
createPortal은 root가 아닌 다른 곳에서 렌더링 할 수 있게 해준다.
ReactDOM.createPortal(child, container)
첫 번째 인자는 컴포넌트, 두번째 인자는 컴포넌트가 들어갈 곳
나는 모달창이기 때문에 document.body에 넣었다.
** 사용 **
export default function Home() {
const { showAlert, onCloseSearchAlret, onChangeSearch, onClickSearch } =
useSearch(); // 코드 중복으로 useSearch 커스텀 훅으로 수정
const { isShowing, modalToggle } = useModal();
return (
<>
<Head>
<title>Go Camping</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Wrap>
<MainWrap>
<Button
onClick={() => {
modalToggle();
}}
className="review"
>
요즘 캠핑 후기 보기
</Button>
{/* 캠핑 후기 준비중 alert */}
<Modal
isShowing={isShowing}
hide={modalToggle}
message="준비 중입니다!"
/>
<SearchBox>
<h2>Dayily camping</h2>
<div className="search">
<DropDown isMain={true} onChangeSearch={onChangeSearch} />
<Button onClick={onClickSearch} className="search_btn">
<span className="mobile">검색하기</span>
<span className="sr_only">검색</span>
</Button>
</div>
</SearchBox>
{/* 지역 미선택시 alert */}
{showAlert && (
<Modal
isShowing={showAlert}
hide={onCloseSearchAlret}
message="지역을 선택해주세요!"
/>
)}
</MainWrap>
</Wrap>
</>
);
}
지역 미선택 alert은 useSearch 훅으로 만들어놨었기 때문에 코드 수정을 했다.
useSearch() 수정 코드
더보기
export function useSearch() {
const [region, setRegion] = useState<string>("");
const [subRegion, setSubRegion] = useState<string | null>(null);
const router = useRouter();
const [showAlert, setShowAlert] = useState<boolean>(false);
const onChangeSearch = (region: string, subRegion: string | null) => {
setRegion(region);
setSubRegion(subRegion);
};
const onClickSearch = async (): Promise<void> => {
if ((region !== null && subRegion !== null) || region === "전체") {
await router
.push({
pathname: "/campingList",
query: { region, subRegion },
})
.catch((error) => {
console.log(error);
});
} else {
setShowAlert(true);
}
};
const onCloseSearchAlret = () => {
setShowAlert(false); // 모달 닫기
};
return {
showAlert,
region,
subRegion,
onCloseSearchAlret,
onChangeSearch,
onClickSearch,
};
}
https://kimyk60.tistory.com/38
'언어 > Next.js' 카테고리의 다른 글
[Next 고캠핑] 뒤로가기 클릭시 모달창 닫기 (0) | 2024.08.12 |
---|---|
[Next 고캠핑] 모달 만들기 (1) | 2024.07.31 |
[Next 고캠핑] 드롭다운 선택으로 검색을 해보자 (타입스크립트) (0) | 2024.07.25 |
[Next 고캠핑] 페이지네이션 커스텀하기 (1) | 2024.07.24 |
[Next 고캠핑] 입지 구분 아이콘으로 하기 (0) | 2024.07.17 |