dev/react

모달창

wlrn566 2023. 3. 24. 21:26

입력폼을 팝업으로 띄우려고 하기 위해서는 팝업표시 여부를 상태관리 해줘야한다.

 

Modal이라는 컴포넌트를 만들고 NewPost를 Modal이라는 컴포넌트 내부로 옮겨준다.

 

import { useState } from "react";
import Modal from "./Modal";

import NewPost from "./NewPost";
import Post from "./Post";
import classes from './PostsList.module.css'

function PostsList() {
  const [enteredBody, setEnteredBody] = useState('');
  const [enteredAuthor, setEnteredAuthor] = useState('');
  
  function bodyChangeHandler(event) {
    setEnteredBody(event.target.value);
  }
  
  function authorChangeHandler(event) {
    setEnteredAuthor(event.target.value);
  }
  
  // 모달창 상태관리
  const [modalIsVisible, setModalIsVisible] = useState(true);
  function hideModalHandler() {
    setModalIsVisible(false);
  }

  return (
    <>
      <Modal onClose={hideModalHandler}>
      	<NewPost onBodyChange={bodyChangeHandler} onAuthorChange={authorChangeHandler}/>
      </Modal>
      <ul className={classes.posts}>
        <Post author = {enteredAuthor} body= {enteredBody}/>
        <Post author = "ruby" body = "hello react"/>
      </ul>
    </>
  );
}

export default PostsList;

 

import classes from "./Modal.module.css"

function Modal({children, onClose}) {
  return (
    <>
      <div className={classes.backdrop} onClick={onClose}/>
      <dialog open className={classes.modal}>{children}
      </dialog>
    </>

  );
}

export default Modal;
// dialog의 open속성을 통해 팝업창을 호출한다. 기본값은 true

 

객체 구조 분해를 통해 props.children이 아닌 children키에 바로 접근할 수 있다.
여기서 children은 해당 컴포넌트 태그 내부의 컴포넌트 내용을 전달해주는 예약어이다.
여기서는 NewPost가 된다.

 

그리고 Modal의 표시여부를 상태관리하기 위해 useState등록을 하고 props로 onClose키값에 함수를 넣고 Modal에 전달해준다.

배경을 클릭했을 때 숨기기 위해 onClick으로 onClose를 넣어준다.

 

 

modalIsVisible의 값을 통해 숨겨줘야 하므로 조건을 달아준다.

 

let modalContent;

if(modalIsVisible) {
    modalContent = (
      <Modal onClose={hideModalHandler}>
        <NewPost onBodyChange={bodyChangeHandler} onAuthorChange={authorChangeHandler}/>
      </Modal> 
    );
}

 

return (
    <>
      {modalContent}
    </>
  );

 

이런식으로 컴포넌트 자체를 값에 할당하여 주거나

 

return (
  <>
    {modalIsVisible &&    
      (<Modal onClose={hideModalHandler}>
        <NewPost onBodyChange={bodyChangeHandler} onAuthorChange={authorChangeHandler}/>
      </Modal>)}
  </>
);

 

&& 를 통해 true인 경우만 나오게끔 해주거나

 

return (
  <>
    {modalIsVisible ?     
      <Modal onClose={hideModalHandler}>
        <NewPost onBodyChange={bodyChangeHandler} onAuthorChange={authorChangeHandler}/>
      </Modal> 
    : null}
  </>
);

 

3항 연산자로 처리할 수 있다.

 

공통 헤더 컴포넌트를 달아주어 팝업을 닫고 열수 있게 만들어 본다.

 

import { MdPostAdd, MdMessage } from 'react-icons/md';
import classes from './MainHeader.module.css';

function MainHeader({ onCreatePost }) {
  return (
    <header className={classes.header}>
      <h1 className={classes.logo}>
        <MdMessage />
        React Poster
      </h1>
      <p>
        <button className={classes.button} onClick={onCreatePost}>
          <MdPostAdd size={18} />
          New Post
        </button>
      </p>
    </header>
  );
}

export default MainHeader;

 

npm install react-icons로 아이콘을 사용하기 위한 라이브러리를 설치 해준다.

 

import { useState } from "react";

import MainHeader from "./components/MainHeader";
import Post from "./components/Post";
import PostsList from "./components/PostsList";

function App() {
  // 모달창 상태관리
  const [modalIsVisible, setModalIsVisible] = useState(false);

  function hideModalHandler() {
    setModalIsVisible(false);
  }

  function showModalHandler() {
    setModalIsVisible(true);
  }

  return (
    <>
      <MainHeader onCreatePost={showModalHandler}/>
      <main>
        <PostsList isPosting={modalIsVisible} onStopPosting={hideModalHandler}/>
      </main>;
    </>
  );
}

export default App;

 

App.jsx에 헤더를 넣고 헤더를 통해 팝업창을 상태관리 할 것이므로 PostsList.jsx에 있던 모달창 상태관리를 가져와 넣어준다.

동일하게 MainHeader에 onCreatePost 라는 props로 함수를 넘겨주고 MainHeader에서 받아서 처리한다.

그리고 PostsList에 isPosting, onStopPosting props를 전달하여 PostsList내부의 Modal을 관리해준다.

 

즉 App에서 팝업창 상태관리를 MainHeader와 PostsList와 연결시켜주는 것이다. 그리고 PostsList는 App에서 받은 값으로 Modal표시여부 조건을 처리해준다.