ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

Issue

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์—์„œ ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ์ด๋“œ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ Modal ์ฐฝ์ด ๋„์›Œ์ ธ ํ™”๋ฉด์— ๋žœ๋”๋ง๋œ๋‹ค.

 

์ด๋ฅผ ์œ„ํ•ด Modal ์ฐฝ์— ๋Œ€ํ•œ Presentation Component์ธ BodyBlackout ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•˜์˜€๋‹ค.

mport { useDispatch } from "react-redux";
import styled from "styled-components";

const BodyBlackout = ({
  modalSort,
  setAuthModalVisible,
  isVisibleAuthModal,
}) => {
  const dispatch = useDispatch();
  if (isVisibleAuthModal)
    document.querySelector("body").style.setProperty("overflow", "hidden");
  return (
    <BodyBlackoutStyle
      onClick={() => {
        dispatch(setAuthModalVisible(modalSort));
      }}
    />
  );
};

const BodyBlackoutStyle = styled.div`
  position: absolute;
  z-index: 1010;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.65);
  cursor: pointer;
`;

export default BodyBlackout;

ํ•ด๋‹น BodyBlackout ์ปดํฌ๋„ŒํŠธ์— ๋„˜๊ฒจ์ง„ props๊ฐ’์„ ํ†ตํ•ด ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ ์„ค์ • ๊ฐ’์— ๋งž๊ฒŒ Modal ์ฐฝ์ด ๋„์›Œ์ง€๋„๋ก ํ•˜์˜€๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์ด Register Container Component ๋‚ด์—์„œ react-redux store ๋‚ด์—์„œ ํ˜„์žฌ Modal ์ฐฝ์ด ํ™”๋ฉด์— ๋ณด์—ฌ์ง€๋Š”์ง€์— ๋Œ€ํ•œ ์—ฌ๋ถ€๋ฅผ ์ €์žฅํ•˜๋Š” isVisibleAuthModal state ๊ฐ’์„ ์„ค์ •ํ•˜์˜€๊ณ  ์ด๋ฅผ BodyBlackout Component์— props๋กœ ์ „๋‹ฌํ•˜๋Š” ๋กœ์ง์œผ๋กœ Modal ์ฐฝ์„ ๋žœ๋”๋ง ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค.

 

์•ก์…˜์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ Modal ์ฐฝ์ด ๋ณด์—ฌ์ง€๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•ด์ฃผ๋Š” ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜ setAuthModalVisible๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ํ•ด๋‹น ์•ก์…˜ ์ƒ์„ฑ ํ•จ์ˆ˜์— ์ธ์ž๋กœ๋Š” ํ˜„์žฌ ํ™œ์„ฑํ™”๋˜์–ด์•ผ ํ•  form์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค.

    ( ... )

const SET_AUTHMODALVISIBLE = "auth/SET_AUTHMODALVISIBLE";

	( ... )

export const setAuthModalVisible = createAction(
  SET_AUTHMODALVISIBLE,
  form => form
);

const initialState = {
  login: {
    ( ... )
    isVisibleAuthModal: false,
  },
  register: {
    ( ... )
    isVisibleAuthModal: false,
    is_receive_email: false,
  },
};

const auth = handleActions(
  {
    ( ... )
    [SET_AUTHMODALVISIBLE]: (state, { payload: form }) =>
      produce(state, draft => {
        draft[form].isVisibleAuthModal = !state[form].isVisibleAuthModal;
      }),
  },
  initialState
);

export default auth;

 

์ด๋ ‡๊ฒŒ auth module์—์„œ ์„ค์ •ํ•œ isVisibleAuthModal๊ณผ setAuthModalVisible๋ฅผ Register Container Component ๋‚ด์—์„œ ๊ฐ€์ ธ ์™€ Auth Presentation Component ๋‚ด์—์„œ ์•ก์…˜์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ์— ํ•ด๋‹น ์•ก์…˜ ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด redux-store์— ์žˆ๋Š” isAuthModalVisible state๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค.

import React, { useCallback, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
  setAuthModalVisible,
} from "../../modules/auth";
import BodyBlackout from "../../components/common/BodyBlackout";

const RegisterFormContainer = () => {
  const dispatch = useDispatch();

  const isVisibleAuthModal = useSelector(
    ({ auth }) => auth.register.isVisibleAuthModal
  );

	( ... )

  if (isVisibleAuthModal) {
    return (
      <>
        <BodyBlackout
          modalSort="register"
          setAuthModalVisible={setAuthModalVisible}
          isVisibleAuthModal={isVisibleAuthModal}
        />
        <AuthTemplate>
          <RegisterForm
            form={form}
            checkCurrentAdvertiseAccess={checkCurrentAdvertiseAccess}
            isCorrectPasswordPattern={isCorrectPasswordPattern}
            authError={authError}
            changeRegisterInputValue={changeRegisterInputValue}
            inputValueDuplicationCheck={inputValueDuplicationCheck}
            sendToEmailForVerificationCode={sendToEmailForVerificationCode}
            signup={signup}
          />
        </AuthTemplate>
      </>
    );
  } else return null;
};

export default RegisterFormContainer;

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋‹ค ๋ณด๋‹ˆ, ๊ธฐ๋Šฅ ์ƒ์—๋Š” ๋ฌธ์ œ๋Š” ์—†์ง€๋งŒ Modal ์ฐฝ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ modalVisible state๊ฐ’์„ store์— ์ผ์ผํžˆ ์ €์žฅํ•ด๋‘์–ด์•ผ ํ•ด์„œ ๋น„ํšจ์œจ์ ์ด์—ˆ์œผ๋ฉฐ ๋ฐ์ดํ„ฐ ํ๋ฆ„ ์ƒ modal ๋žœ๋”๋ง ๊ด€๋ จ state ๊ฐ’์„ ๊ธฐ๋Šฅ ์ปดํฌ๋„ŒํŠธ๋“ค์˜ state๊ฐ’์— ์ €์žฅํ•ด๋‘๋Š” ๊ฑด ๋‹ค์†Œ ๋งž์ง€ ์•Š์œผ๋ฉฐ ์ฝ”๋“œ๋ฅผ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฌธ์ œ๋ฅผ ์•ผ๊ธฐ์‹œ์ผฐ๋‹ค.

 

์ด๋ฅผ ์œ„ํ•ด custom Hooks๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ react-redux ๋Œ€์‹ ์— Modal Visible๋ฅผ ์ปจํŠธ๋กคํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ๋ฆฌํŒฉํ† ๋งํ•˜์˜€๋‹ค.

 

Refactor

์šฐ์„  Modal Template ์—ญํ• ์„ ํ•ด์ค„ Modal Component๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•˜์˜€๋‹ค.

import React, { Fragment } from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";

const Modal = ({ isShowing, hide, children }) => {
  if (isShowing) {
    document.body.style.setProperty("overflow", "hidden");
    return ReactDOM.createPortal(
      <Fragment>
        <BodyBlackoutStyle onClick={hide} />
        {children}
      </Fragment>,
      document.body
    );
  } else return null;
};

const BodyBlackoutStyle = styled.div`
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.65);
  cursor: pointer;
  z-index: 1100;
`;

export default Modal;

์šฐ์„  React.createPortal๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Modal Component๊ฐ€ ํŠน์ •ํ•œ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์— ๊ท€์†๋˜์ง€ ์•Š๊ณ  ๋…๋ฆฝ์ ์œผ๋กœ ๋žœ๋”๋ง๋  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค.

 

 

https://ko.reactjs.org/docs/portals.html

 

Portals – React

A JavaScript library for building user interfaces

ko.reactjs.org

React.createPortal๋ฅผ ์‚ฌ์šฉํ•  ์ƒ์œ„ ๋…ธ๋“œ๋“ค์˜ overflow ์š”์†Œ๋‚˜ z-index์— ๋Œ€ํ•œ ์šฐ์„  ์ˆœ์œ„ ๋“ฑ ๋ถ€๋ชจ ๋…ธ๋“œ์˜ ์Šคํƒ€์ผ์— ๋Œ€ํ•ด์„œ ๋ฐฉํ•ด๋ฅผ ๋ฐ›์ง€ ์•Š๊ณ  ์›ํ•˜๋Š” ์„ค์ •์— ๋งž์ถฐ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์˜ ์™ธ๋ถ€์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ๋žœ๋”๋งํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋˜ํ•œ Modal ์ฐฝ์ด ํ™”๋ฉด์— ๋„์›Œ์ ธ ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ์Šคํฌ๋กค์ด ๋™์ž‘ํ•˜๋ฉด ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ์— isShowing ๊ฐ’์ด true์ผ ๊ฒฝ์šฐ์—” body ํƒœ๊ทธ scroll style ๊ฐ’์„ hidden์œผ๋กœ ์„ค์ •ํ•ด์ฃผ์—ˆ๋‹ค.

 

๋‹ค์Œ์œผ๋ก  Modal ์ฐฝ๊ณผ ๊ด€๋ จ๋œ state๊ฐ’๊ณผ ํ•ด๋‹น state๊ฐ’๋“ค์„ ์ด์šฉํ•˜์—ฌ Modal ์ฐฝ ๊ด€๋ จ ์„ค์ •์„ ๋‹ด๋‹นํ•ด ์ค„ useModal ์ด๋ผ๋Š” custom Hooks์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค.

import { useState } from "react";

const useModal = () => {
  const [isShowing, setIsShowing] = useState(false);
  const [modalInfo, setModalInfo] = useState([]);

  const setModalVisible = (...modalInfo) => {
    setModalInfo(modalInfo);
    setIsShowing(!isShowing);
  };

  return { isShowing, modalInfo, setModalVisible };
};

export default useModal;

setModalVisible ํ•จ์ˆ˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” Trigger ์š”์†Œ(ex. ํšŒ์›๊ฐ€์ž… ๋ฒ„ํŠผ)์— ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋กœ ์ง€์ •ํ•ด ๋‘๊ณ  ํ•ด๋‹น ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ํ˜„์žฌ ์ปดํฌ๋„ŒํŠธ์— ์ปค์Šคํ„ฐ๋งˆ์ด์ง•๋œ Modal ์ฐฝ์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” modalInfo๋ฅผ ์ธ์ž๋กœ ๋ฐ›์•„ state๊ฐ’์„ ์„ค์ •ํ•œ๋‹ค.

 

์ด๋•Œ modalInfo์™€ ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค ๋ฐ›์•„์•ผ ๋˜๋Š” ์ •๋ณด๊ฐ€ ์ƒ์ดํ•˜๊ธฐ ๋•Œ๋ฌธ์— Rest Parameter ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ›์•„ ์˜จ ์ธ์ž๊ฐ’๋“ค์„ ๋ฐฐ์—ด์— ์ €์žฅํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค.

 

๋งˆ์ง€๋ง‰์œผ๋ก  Modal ์ฐฝ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ Presentation Component ๋‚ด์—์„œ Modal Template ๊ธฐ๋Šฅ์„ ํ•˜๋Š” Modal ์ปดํฌ๋„ŒํŠธ์™€ Modal ๊ด€๋ จ ์ปจํŠธ๋กค๋ฅผ ๋‹ด๋‹นํ•˜๋Š” useModal ์ปดํฌ๋„ŒํŠธ๋ฅผ importํ•˜์—ฌ ํ•„์š”ํ•œ ๋™์ž‘์— ๋งž๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค.

	( ... )
    
import Modal from "../../components/common/Modal";
import useModal from "../../hooks/useModal";
import ModalTemplate from "../../components/common/ModalTemplate";
import MakeRoomInfoModal from "../../components/common/MakeRoomInfoModal";

const MainForm = ({
	( ... )
}) => {
  const { isShowing, modalInfo, setModalVisible } = useModal();

  	( ... )

  return (
    <Container>
      <Modal isShowing={isShowing} hide={setModalVisible}>
        <ModalTemplate>
          <MakeRoomInfoModal modalInfo={modalInfo} hide={setModalVisible} />
        </ModalTemplate>
      </Modal>
      
      ( ... )
      
    </Container>
  );
};

	( ... )

export default MainForm;

 

๋™์ž‘ ์˜์ƒ

 

Reference

https://upmostly.com/tutorials/modal-components-react-custom-hooks

 

๋Œ“๊ธ€
๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
TAG
more
ยซ   2024/10   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
๊ธ€ ๋ณด๊ด€ํ•จ