[개발일기] 파이어베이스로 만든 일기장에 추가기능 구현하기 - context API 활용해서 모달 구현하기

박소정·2022년 9월 29일
1
post-thumbnail

지난 포스팅에서 달력을 구현한 후, 통일성이 없었던 Nav스타일을 수정하고, 일기 입력폼을 불러올 +버튼도 추가하였다!

+버튼을 클릭하면 일기를 작성할 수 있는 폼이 뜨게 할려고 하는데, 이 부분은 context api를 활용해서 해보려고 한다.

우선 처음을 작성했던 코드는

import { createContext, useState } from "react";

const DiaryContext = createContext();

const DiaryContextProvider = ({ children }) => {
  const [openState, setOpenState] = useState(false);
  const updateOpenState = (date) => {
    console.log("click");
  };

  const contextValue = {
    isOpen: openState,
    updateOpenHandler: updateOpenState,
  };
  return (
    <DiaryContext.Provider value={contextValue}>
      {children}
    </DiaryContext.Provider>
  );
};

export { DiaryContext, DiaryContextProvider };

처음에는 이렇게 작성해두고 클릭했을때 콘솔에 찍히는지 확인을 해보려고 했는데,
이런 에러가 났다! 대체 와이..ㅠㅜ
provider로 감싸주고 value도 제대로 전달해주었는데 아예 전달 자체가 되지 않는 상황이었다.
defaultValue는 어떠한 provider에도 할당되지 않았을 경우에 사용된다고 해서 영향이 없을것같지만 혹시나 싶어defaultValue도 채워봤지만 에러도 뜨지 않았다!
context api를 제대로 이해하지 못하고 있는건가 싶어 다시 공식문서를 읽어보고 여러가지 사용 예시들을 읽어보다가 문득 'provider을 다들 app.js에 감싸네? 난 어디에 넣었지...?' 하는 생각이 들어 살펴봤더니 calendar을 감싸고 있었다!!
provider을 app.js로 옮겨주었더니 콘솔에 click이 찍히기 시작했다!!!!!
전역상태 관리인데 왜 calendar만 감싸고 삽질을 하기 시작했던 것일까!
좀 더 공부해보니

provider는 모든 컴포넌트에 접근이 가능하여 상태를 가져올 수 있는 루트 컴포넌트가 필요하므로 index.js 또는 app.js에서 정의되어야 한다고 한다!!

이렇게 또 잊지못할 추억 하나 저장...⭐️

제대로 작동하는 것 같으니 전달해줘야하는 상태를 좀더 구체적으로 바꾸어 주었다.

import { createContext, useState } from "react";

const DiaryContext = createContext();

const DiaryContextProvider = ({ children }) => {
  const [openState, setOpenState] = useState({
    isOpen: false,
    date: "",
  });
  const updateOpenState = (bool, date) => {
    setOpenState({ isOpen: bool, date: date });
  };

  const contextValue = {
    openState: openState,
    updateOpenHandler: updateOpenState,
  };
  return (
    <DiaryContext.Provider value={contextValue}>
      {children}
    </DiaryContext.Provider>
  );
};

export { DiaryContext, DiaryContextProvider };

openState의 상태값트로 객체를 주어 isOpen으로는 모달이 열렸는지 닫혔는지를, date에는 선택된 날짜(달력의 아무 날짜도 선택하지 않고 +버튼을 클릭했다면 오늘날짜)를 전달해주어 일기장 작성 모달에 전달해주려 한다.

전달형식도 처음에는

이런 형태였는데, 좀더 간결하게 전달하기 위해 date-fns의 format 함수를 사용하여

 <div
        className={classes.addDiary}
        onClick={() => {
          openHandler.updateOpenHandler(
            true,
            format(selectedDate, "yyyyMMMdd")
          );
        }}
      >
</div>


간결하게 바꿔주었다.

다음은 일기장 모달을 만들어서 +버튼을 클릭했을때 일기장 폼이 나오게 만들면 된다!
((나 완전 안전주의자ㅎㅅㅎ))
또 원하는 대로 동작하는지 확인하기 위해 시험삼아

{openHandler.openState.isOpen && <button>hello</button>}

이렇게 코드를 넣어 isOpen이 true일때 hello 버튼이 나오는지 확인해보았다

두둥 성공!

modal.jsx파일을 만들어 만들어 두었던 diaryform을 import 했더니

두둥 떴다!

좀더 모달처럼 작업을 해주고, diaryform에 모달을 닫을 수 있는 버튼도 추가해주었더니

제대로 작동하였다.

좀더 모달처럼 해주기 위해 모달의 바탕 부분을 클릭해도 꺼질 수 있도록

const Modal = () => {
  const openHandler = useContext(DiaryContext);
  return (
    <div
      className={classes.diaryFormContainer}
      onClick={() => {
        openHandler.updateOpenHandler(false, "");
      }}
    >
      <DiaryForm />
    </div>
  );
};

이렇게 코드를 추가해 주었는데 이벤트 버블링이 일어났다!

모달의 바탕 부분을 클릭해도 꺼질 수 있도록 구현했을때 버블링이 일어나서 모달에 e.stopPropagation();을 추가했는데 계속 버블링이 일어났다. form에 추가해도 계속 일어나구 말이야...?
콘솔에 찍어봐도

이렇게 모달에 찍히는데!!

이것저것 찾아보다 이전에 구현했던 내 코드를 보고 답을 얻었다.
이전에 구현했던 모달에서는

<ModalBG>
  opacity가 들어가있는 모달 바탕
  <Modal onclick={e => e.stopPropagation()}>
  진짜 내용을 감싸는 바탕!
  <content>폼이나 진짜 내용들!</content>
</<Modal>
  </ModalBG>

이렇게 진짜 내용을 감싸는 바탕이 한 겹 더 있어 여기서 버블링을 막아주고 있었다. 당시에 구현할때는 ui상으로 저 배경이 있으면 좋을것 같아 깔아주고 위의 진짜 컨텐츠를 클릭해도 밑으로 전달되면 안되니까 저기에 stopPropagation()을 넣어준 것이었는데 구현상으로도 필요한 것이었다니!!

이렇게 또 잊지못할 기억을 저장...⭐️ 하며 diaryform 모달도 완성하였다!
이제 diaryform에 사진도 추가하고, css도 입히면 어느정도 구현은 끝날것 같다!

0개의 댓글