📌 모달 구현
1. 모달의 오픈 여부를 알 수 있는 상태값이 있는 slice 만들기
// ModalSlice.jsx
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
modal: false,
};
export const modalSlice = createSlice({
name: 'modal',
initialState,
reducers: {
showModal: (state) => {
state.modal = true;
},
closeModal: (state) => {
state.modal = false;
},
},
});
export default modalSlice.reducer;
export const { showModal, closeModal } = modalSlice.actions;
2. store에 만든 모달 slice 추가
// Store.jsx
import { configureStore } from "@reduxjs/toolkit";
import modalReducers from "./ModalSlice";
const store = configureStore({
reducer: {
modal: modalReducers,
},
});
export default store;
3. 모달 component 만들기
style의 width, height는 prop로 지정하게 해 재사용성 높임
ReactDom의 createPortal를 사용하여 가장 상단에 위치하도록 함
react-modal 라이브러리 사용
라이브러리의 Modal 태그를 사용하면 isOpne, onRequestClose, stytle 등 자체 속성을 통해
여닫힘, 바깥 부분 클릭시 닫힘 등의 기능을 사용할 수 있다.
import React from 'react';
import styled from 'styled-components';
import { IoClose } from 'react-icons/io5'; // 아이콘 추가
import Modal from 'react-modal';
import { createPortal } from 'react-dom';
import { useSelector, useDispatch } from 'react-redux';
import { closeModal } from '../store/ModalSlice';
const DialogBox = styled.div``;
const FormContainer = styled.div``;
const CloseButton = styled.button` // 닫기 버튼 설정
position: absolute;
right: 3%;
top: 5%;
border: none;
background-color: inherit;
font-size: 1rem;
cursor: pointer;
`;
ModalContainer.defaultProps = { // 모달 props 기본값
children: '',
w: '50%',
h: '70%',
overflow: 'auto',
};
function ModalContainer({ children, w, h, overflow }) {
const modalOpen = useSelector((state) => state.modal.modal);
const dispatch = useDispatch();
return createPortal(
<Modal
isOpen={modalOpen}
onRequestClose={() => dispatch(closeModal())}
ariaHideApp={false}
style={{
overlay: {
position: 'fixed',
backgroundColor: 'rgba(255, 255, 255, 0.75)',
},
content: {
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
padding: '2rem',
zIndex: 100,
width: `${w}`,
height: `${h}`,
overflow: `${overflow}`,
},
}}
>
<DialogBox>
<CloseButton
onClick={() => {
dispatch(closeModal());
}}
>
<IoClose size={25} />
</CloseButton>
<FormContainer>{children}</FormContainer>
</DialogBox>
</Modal>,
document.getElementById('modal'),
);
}
export default ModalContainer;
라이브러리 미사용
import { useEffect, useRef } from "react";
import { createPortal } from 'react-dom';
import { useSelector, useDispatch } from 'react-redux';
import { closeModal } from '../store/ModalSlice';
export default function Modal({ child, w ='50%', h='70%' }) {
const modalOpen = useSelector((state) => state.modal.modal);
const dispatch = useDispatch();
const modalRef = useRef<HTMLDivElement>(null);
useEffect(() => {
// 모달창 바깥 영역 클릭시, 모달창 닫기
const handleClickBackground = (event: MouseEvent) => {
if (modalRef.current && !modalRef.current.contains(event.target as Node)) {
dispatch(closeModal())
}
};
document.addEventListener('mousedown', handleClickBackground);
// 모달 컴포넌트 사라질 때, 이벤트핸들러 제거
return () => {
document.removeEventListener('mousedown', handleClickBackground);
};
});
return createPortal(
{ isModalOpen && (<div
ref={modalRef}
style={`width:${w}, height:${h}`}>
<button
type="button"
onClick={() => dispatch(closeModal())}
>X</button>
<div>
{children}
</div>
</div>
)}
)
}
index.html에 모달 넣기
모든 페이지보다 상위에 넣어야 하므로 root 바로 아래에 넣어줌
...
<body>
<div id="root"></div>
<div id="modal"></div>
</body>
📌 모달 사용법
1. 상단에 사용할 훅 불러오기
import ModalContainer from "./../components/Modal";
import { useDispatch, useSelector } from "react-redux";
import { showModal } from "../store/ModalSlice";
2. 컴포넌트에 dispatch와 modal상태값을 불러오기
const dispatch = useDispatch();
const modalOpen = useSelector((state) => state.modal.modal);
3. 모달을 띄울 버튼에 onClick 넣어서 모달 상태 변경하기
onClick={() => dispatch(showModal())}
4. 띄울 모달을 리턴 부분에 추가하기
<ModalContainer w="세로길이" h="가로길이">모달안에 들어갈 내용</ModalContainer>
* w, h를 넘겨주지 않으면 기본 50% * 70% 크기
* 한 화면에서 모달 여러 개를 사용한다면 해당 컴포넌트 안에서 각 모달의 상태를 관리할 것
'Programming > Client' 카테고리의 다른 글
[React] 프론트단에서 페이지네이션 구현하기 (0) | 2023.02.15 |
---|---|
[Javascript] formData로 이미지, 문자열 묶어서 전달하기 (0) | 2023.01.08 |
[Javascript] 모듈로 설정된 파일의 변수는 전역 변수가 아니다! (0) | 2023.01.06 |
[Javascript] array.reduce() 콜백함수 속 증감연산자 (0) | 2022.05.03 |
[Javascript] Array.fill()로 2차원 배열을 만들면 안되는 이유 (0) | 2022.05.02 |