[Next.js] 모달창 정말 쉽게 구현하기

JunSeok·2023년 2월 23일
14

Movie-inner 프로젝트

목록 보기
8/13
post-thumbnail

구현 목표

  • 모달 버튼 클릭하면 모달창이 화면에 뜬다.
  • 모달창은 정중앙에 위치하며 모달을 제외한 뒷배경은 어둡게 한다.
  • 뒤로가기 또는 뒷배경 클릭하면 모달창을 나갈 수 있게 한다.
    - 모달창 자체를 클릭할 때는 밖에 나가지 않게 한다. => e.stopPropagation() 사용

구현

모달 버튼 만들기

  • 모달 버튼 클릭 유무를 저장할 state를 만든다. 보통 boolean 값으로 한다.
  • 모달 화면을 띄울 컴포넌트 내에 모달 버튼을 만들고, 버튼 클릭시 모달 버튼 클릭 유무를 설정하는 state 함수를 실행한다.
  • state가 true면 만들어놓은 모달 컴포넌트를 화면에 띄운다.
  • state함수를 모달 컴포넌트 props로 전달한다. => 모달 내에서 모달을 나갈 수 있어야 하기 때문
// 모달 화면을 띄울 컴포넌트
import { useState } from 'react'
import { AiOutlineSearch } from 'react-icons/ai'
import { BsPencilFill } from 'react-icons/bs'
import FeedSearchModal from './Search/FeedSearchModal'

const FeedRemote = () => {
  	// 모달 버튼 클릭 유무를 저장할 state
    const [showModal, setShowModal] = useState(false)
    
	// 버튼 클릭시 모달 버튼 클릭 유무를 설정하는 state 함수
    const clickModal = () => setShowModal(!showModal)

    return (
        <>
            <div>
      			// 돋보기 모양 아이콘을 클릭하면 모달창이 뜬다.
                <AiOutlineSearch onClick={clickModal} size={60}></AiOutlineSearch>
            </div>
			// state가 true면 만들어놓은 모달 컴포넌트를 화면에 띄운다.
			// FeedSearchModal로 state함수를 props로 전달한다. => 모달 내에서 모달을 나갈 수 있어야 하기 때문
            {showModal && <FeedSearchModal clickModal={clickModal} />}
        </>
    )
}

export default FeedRemote

실제 사용할 모달 컴포넌트 구현하기

이제 화면에 띄울 모달 컴포넌트만 만들면 된다.

모달 스타일 구현

  • 모달창은 정중앙에 두며, 모달창을 제외한 뒷배경은 어둡게 한다.
  • 스타일링은 emotion을 사용
// modalStyle.tsx
import styled from '@emotion/styled'

// 모달 창 뒷배경
export const SearchModalBox = styled.div`
	position: fixed;
	top: 0;
    left: 0;
    width: 100%;
    height: 100%;
	background-color: rgba(0, 0, 0, 0.4);
    display: flex;
    justify-content: center;
    align-items: center;
`

// 여기에 만들고 싶은 모달 스타일 구현
export const SearchModalContent = styled.div`
    padding: 1.5rem 3rem;
    width: 28.125rem;
    border-radius: 0.313rem;
    display: flex;
    flex-direction: column;
    background-color: #ffffff;
      > div:nth-of-type(1) {
        background-color: #c8c7c7;
        border-radius: 0.313rem;
      }
      > input {
        display: flex;
        align-items: center;
        margin-top: 0.625rem;
        border: 0.063rem solid gray;
        padding: 0.8rem 1rem;
        font-size: 1rem;
      }
      > div {
        display: flex;
        justify-content: space-evenly;
        margin-top: 1.25rem;
        > button {
          border: none;
          width: 6.875rem;
          padding: 0.8rem 1.8rem;
          font-size: 0.9rem;
        }
        > :nth-of-type(2) {
          background-color: #e15050;
        }
}
`

모달 컴포넌트 구현

모달 컴포넌트를 띄울 컴포넌트로부터 state 함수를 props로 전달받는다.

  • 뒷배경을 클릭하면 모달을 나갈 수 있게 해야 하므로 뒷 배경 onClick에 state함수를 넣는다.
  • 뒷배경이 아닌 content를 클릭했을 때는 모달을 나가면 안되기 때문에 content의 onClick에 e.stopPropagation()를 넣어줘야 한다.
    - 웹페이지에서는 click event가 발생하는 엘리먼트 기준 상위 엘리먼트로 전파된다.
    - e.stopPropagation()은 상위 엘리먼트들로의 이벤트 전파를 중단시킨다.
import InputLabel from '@mui/material/InputLabel'
import MenuItem from '@mui/material/MenuItem'
import FormControl from '@mui/material/FormControl'
import Select, { SelectChangeEvent } from '@mui/material/Select'
import { useState } from 'react'
import { SearchModalBox, SearchModalContent } from './FeedSearchModal.style'
import { toast } from 'react-toastify'
import router from 'next/router'

const FeedSearchModal = (props) => {
  	// 전달받은 state 함수
    const { clickModal } = props
    
    // 글과 관련이 없음
    const [search, setSearch] = useState('')
    const [type, setType] = useState('')
    const handleChange = (e) => setSearch(e.target.value)
    const typeChange = (e: SelectChangeEvent) => setType(e.target.value)
    const clickSearch = async () => {}
    return (
      	// 뒷배경을 클릭하면 모달을 나갈 수 있게 해야하므로 뒷 배경 onClick에 state함수를 넣는다.
        <SearchModalBox onClick={clickModal}>
      		// 모달을 닫는 state함수가 아래로 전파되는 것을 막아줌
            <SearchModalContent onClick={(e) => e.stopPropagation()}>
                <FormControl size='small'>
                    <InputLabel id='demo-select-small'>검색</InputLabel>
                    <Select labelId='demo-select-small' id='demo-select-small' value={type} label='type' onChange={typeChange}>
                        <MenuItem value={'title'}>제목</MenuItem>
                        <MenuItem value={'content'}>내용</MenuItem>
                        <MenuItem value={'titleAndContent'}>제목+내용</MenuItem>
                        <MenuItem value={'writer'}>작성자</MenuItem>
                    </Select>
                </FormControl>
                <input type='text' placeholder='검색' onChange={handleChange} />
                <div>
                    <button onClick={clickModal}>뒤로가기</button>
                    <button onClick={clickSearch}>검색</button>
                </div>
            </SearchModalContent>
        </SearchModalBox>
    )
}

export default FeedSearchModal

모달을 이용한 검색 기능이 궁금하다면

[Next.js] 커뮤니티 검색 기능(Material-UI)

더 많은 코드를 보고 싶다면

프론트엔드 코드 github

profile
최선을 다한다는 것은 할 수 있는 한 가장 핵심을 향한다는 것

2개의 댓글

comment-user-thumbnail
2023년 7월 14일

아주 큰 도움이 됐습니다 사랑합니다..

답글 달기
comment-user-thumbnail
2024년 4월 18일

모달 구현하는데 다른 프레임워크 쓰려다 다 맘에 안들어서 직접 구현하는거 찾고있었는데 정말 많은 도움 됐습니다 감사합니다 ㅎㅎ

답글 달기