모달창

이병관·2021년 5월 26일
0
post-thumbnail
post-custom-banner

모달이 모꼬


이전에 일할땐 레이어 팝업, 팝업, 모달창을 모조리 섞어 써서 머리가 박살날뻔햇는데 다시 또 모달을 만들 생각에 기분이 좋아지기 시작했다.

여기서 잠깐 정리를 하자면

1) 팝업창

팝업창이란 현재 열려있는 브라우저 페이지에 또다른 브라우저 페이지를 띄우는 것이다.
창 위에 또다른 창이 뿅하고 있는거지.
브라우저에서 이 창을 열고 닫을수있다.

2) 모달창
모달창은 기존의 브라우저 페이지 위에 새로운 윈도우 창이 아닌 레이어를 까는 것을 말한다.
모달창은 제거를 하지 않고도 페이지를 이동하면 같이 사라지고
기존의 페이지와 부모-자식 관계를 갖는다.

그래서 나는 새로 창을 하나 띄우는거보다 모달창을 하나 만들면 아주 손쉽게 끝내 버릴 수 있을거 같아 모달창을 구현하기로 했다.

고통


나는 아주 즐거운 마음으로 Material-ui의 modal부분을 봤다

https://material-ui.com/

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Modal from '@material-ui/core/Modal';

function rand() {
  return Math.round(Math.random() * 20) - 10;
}

function getModalStyle() {
  const top = 50 + rand();
  const left = 50 + rand();

  return {
    top: `${top}%`,
    left: `${left}%`,
    transform: `translate(-${top}%, -${left}%)`,
  };
}

const useStyles = makeStyles((theme) => ({
  paper: {
    position: 'absolute',
    width: 400,
    backgroundColor: theme.palette.background.paper,
    border: '2px solid #000',
    boxShadow: theme.shadows[5],
    padding: theme.spacing(2, 4, 3),
  },
}));

export default function SimpleModal() {
  const classes = useStyles();
  // getModalStyle is not a pure function, we roll the style only on the first render
  const [modalStyle] = React.useState(getModalStyle);
  const [open, setOpen] = React.useState(false);

  const handleOpen = () => {
    setOpen(true);
  };

  const handleClose = () => {
    setOpen(false);
  };

  const body = (
    <div style={modalStyle} className={classes.paper}>
      <h2 id="simple-modal-title">Text in a modal</h2>
      <p id="simple-modal-description">
        Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
      </p>
      <SimpleModal />
    </div>
  );

  return (
    <div>
      <button type="button" onClick={handleOpen}>
        Open Modal
      </button>
      <Modal
        open={open}
        onClose={handleClose}
        aria-labelledby="simple-modal-title"
        aria-describedby="simple-modal-description"
      >
        {body}
      </Modal>
    </div>
  );
}


이걸 어떻게 container presenter부분으로 나누지?

보자마자 숨쉬기가 힘들었다.

자 하지만 늘 내가 말하는것이 뭐다? 차근차근 천천히 하면 뭐든 할 수 있다.

일단 위에 부분을 보자면 함수 부분들과 스타일 부분으로 크게 나눌 수 있을 것 같다. 그리고 스타일은 나중에 styled.js로 따로 정의 할 예정이니 위에서 import한 스타일 관련 함수들은 없어도 무방할것이다.

그렇다면 container에 들어갈 녀석들과 presenter에 들어갈 녀석들을 쉽게 찢어 버릴 수 있다.

//container
export default function CommentPop() {
  return (
    <CommentPopUI
    />
  );
}
.....
//presenter

const CommentPopUI = () => { 
	 <Dialog style={{height:'600px'}}
        //open={true}
        // TransitionComponent={Transition}
        // keepMounted
        onClose={handleClose}
        fullWidth
        maxWidth="lg"
      >
          //내부 스타일 
          </Dialog>
}

이렇게 큰 틀로 나누어 보자.
부연 설명을 하자면
container 부분에선 댓글 수정에 필요한 state들과 쿼리문, 함수들이 존재 할것이고
presenter 부분은 dialog자체는 material-ui에서 정의 한 모달창의 기본 창 모습일 것이니 그 부분은 반드시 살리고
dialog 내부에 원하는 html의 모습을 style로 정의 하고 가져오면 될것이다.

본격적으로 나누기


자 지금 한 작업은 페이지의 동작페이지의 모습을 나눈것 뿐이다.
따라서 '모달 호출' '모달 닫기' 부분을 정의를 해줘야 한다.

위에서 가져온 modal부분을 잠시 유심히 보면
const [open, setOpen] = React.useState(false);부분이 존재한다.
즉 setState를 통해 초기 상태를 false로 만들고 그것의 참, 거짓에 따라 Dialog를 보여줄지 안보여줄지를 정의 할 수 있다.

그렇다면 미리 해당 댓글 수정용 Modal을 켜두고, 그 댓글을 수정하는 요청을 누를 때만 모달창을 보여주고, 해당 댓글의 id를 가져오면 될것이다.

그렇다면 순서도가 다음과 같을것이다

댓글 창 - 댓글 모달창 컨테이너로 값을 넘김 - 모달창 컨테이너가 모달창 presenter로 값을 넘김

그렇다면 댓글창 container에선 모달창을 열고 닫는 state구문과 닫아주는 함수.
댓글창 presenter에선 정의 한 모달창을 불러오고 그것들을 연동 시켜주면 될것이다.

handleClose

모달의 상태를 open ={open}상태로 두지 말고 일단 항상 띄어져 있게 하기 위해 open={true}상태로 둔다.

그렇다면 닫아주는 행위는 부모 컨테이너인 댓글창에서 해줘야 하기 때문에 handleClose 부분을 따로 부모 컨테이너 댓글창으로 넘겨주고 그것을 매개변수로 넘겨주면 될것이다.


//container
export default function CommentPop({handleClose}) {
  return (
    <CommentPopUI
    />
  );
}
.....
//presenter

const CommentPopUI = ({handleClose}) => { 
	 <Dialog style={{height:'600px'}}
        open={true}
        // TransitionComponent={Transition}
        // keepMounted
        onClose={handleClose}
        fullWidth
        maxWidth="lg"
      >
          //내부 스타일. 즉 모달창의 모양을 정의할 html요소들
          </Dialog>
}

presentercontainer에 매개변수로 담아주자
왜 open이 항상 true상태인지는 아래에서 설명하겠다.

그리고 댓글창 부분에서 handleClose를 붙여 넣고, open의 state도 정의 하여 댓글창에서 handleClose를 통해 Open의 State를 조정할 수 있도록 정의 하고, 이를 props를 통해 넘겨주자

//BoardComment.contianer
const [open, setOpen] = useState(false);
....
 const handleClose = () => {
    setOpen(false);
  }
 ...
 
return(
    <BoardCommentUI
    data = {data}
    hadleClickPostComment = {hadleClickPostComment}
    handleOnChange = {handleOnChange}
   .....
    modalComment = {modalComment}
    open = {open}/>
  )

}

그리고 마지막으로 presenter에서 해당 모달창을 위에서 open = {true}상태로 둔 이유는 container부분에서 State상태에 따라 해당 창을 보여주거나 닫아주기 위해 두었다.

자 그렇다면 && 연산자로 현재 container에서 const [open, SetOpen] = useState(false)인 상태가 true가 된다면, modal창이 뜰것이다.

//container에 정의된 handleClose
  const handleClose = () => {
    setOpen(false);
    
    router.push(`/board/${routeChange}`);
  }

위에서 봣던 handleClose에 open상태를 false로 바꾸고, router를 통해 해당 글을 완성한 부분으로 이동시켜준다면. 게임 오버다.
물론 현재는 테스트 코드라 글의 id를 통해 이동하지만, 나중에는 글의 번호로 이동하도록 리팩토링이 필요하다.

중요한점:
1. Dialog로 api를 가져왓다. 나중에는 직접 짜봐야할것같다.
2. 조금 매끄럽지 않은 부분들이 있다. 댓글을 마무리 한 후 끝내야할것같다.
3. 모달창을 Container, Presenter로 나누는 작업을 좀더 연습해야한다.

profile
뜨겁고 매콤하고 화끈하게
post-custom-banner

0개의 댓글