2024.02.08 TIL - 모달창 만들기!, react icons, 트러블슈팅(manifest, input password)

Innes·2024년 2월 8일
0

TIL(Today I Learned)

목록 보기
61/147
post-thumbnail

모달창 만들기

⭐️ css로 모달창 만들기 ⭐️

👍🏻 참고한 블로그

1) 부모 컴포넌트에서 isOpen state로 모달창 열고 닫힘 상태관리

  • 기본값은 false (모달창 안열려있으니까 - display: none)
  • 뭔가 클릭하면 true로 바뀌면서 모달창 열림(display: block)

2) 모달 컴포넌트 조건부 display (open, close의 원리)

  • isOpen이 true이면 display: block
    -> open 했을 때 모달창 보여지게 만듦

  • isOpen이 false이면 display: none
    -> 닫았을 때 모달창 안보이게 만듦

3) 모달창의 css

  • 배경을 연하게 처리, 우선순위(z-index)는 메인화면 < 모달 배경색 < 모달창
  • 모달창의 우선순위(z-index)를 가장 1순위로!

    메인화면은 연하게 만들면서 모달창이 열리는듯한 착시(?)를 주는 것이다!!

4) 모달 컴포넌트 닫으려면

  • isOpen 상태는 부모 컴포넌트에서 관리하고 있으니까 닫기 버튼의 onClick 함수도 부모 컴포넌트에서 관리
    -> props로 함수 내려주기
  • close버튼 누르면 isOpen이 false가 되면서 모달창이 닫히는 로직

🖥️ 모달창 코드 예시

// ✅ Header.jsx (헤더의 로그인 버튼 클릭 시 모달창 열기)

import Modal from '../Login/Modal';

const Header () => {
  // isOpen이 true이면  - 모달창 display: block
  // false이면  - 모달창 display: none
  const [isOpen, setIsOpen] = useState(false);
  
  // isSignUp이 true이면 회원가입 컴포넌트 열기
  const [isSignUp, setIsSignUp] = useState(false);
  
  // isLoggedIn이 trued이면 로그인 상태
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  
  const onModalHandler = () => {
    if (user.userId) {
      setIsLoggedIn(false);
      alert('로그아웃 되었습니다.');
    } else {
      setIsOpen(!isOpen);
      if (isSignUp === true) {
        setIsSignUp(!isSignUp);
      }
    }
  };

  return (
    // ...생략
    <StHeaderBtn onClick={onModalHandler}>Login</StHeaderBtn>
	// ...생략
  
  )
}

// ✅ Modal.jsx (모달창 - 로그인 시 Login, 회원가입 시 SignUp 컴포넌트 열기)

import Login from './Login';
import SignUp from './SignUp';
import * as St from './styles/Login.style';

const Modal = () => {
  const onSignUpHandler = () => {
    setIsSignUp(!isSignUp);
  };

  return (
    <St.Background $isOpen={isOpen}>
      <St.Container>
        {isSignUp ? <SignUp/> : <Login/>}
      </St.Container>
    </St.Background>
  );
};

export default Modal;

// ✅ css (styled-components)
export const Background = styled.div`
  display: ${(props) => (props.$isOpen ? 'block' : 'none')};

  z-index: 10;
  background-color: rgba(0, 0, 0, 0.3);
  width: 100%;
  height: 100vh;
  position: fixed;
  top: 0;
  left: 0;
`;

export const Container = styled.div`
  z-index: 100;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: white;

  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 10px;
  box-sizing: border-box;
  width: 26%;
  min-width: 400px;
  height: 67%;
  min-height: 500px;
  border-radius: 5px;
`;


// ✅ Login.jsx (로그인 모달창)

// 눈모양 아이콘 react icons에서 import
import { FiEye, FiEyeOff } from 'react-icons/fi';

const Login = ({onSignUpHandler}) => {
  
  // 회원가입 클릭시 회원가입 모달창으로 이동 (Header에서 props로 받음)
  const onSignUpHandler = () => {
    setIsSignUp(!isSignUp);
  };

  return (
    <>
      <St.LoginWrapper>
        <St.CloseBtn onClick={onModalHandler}>x</St.CloseBtn>
        <St.LogoName>Travel Vibe</St.LogoName>
        <St.LoginTitle>로그인</St.LoginTitle>
        <St.IdPwWrapper>
          <St.InputContainer>
            <St.LoginInput
              placeholder='이메일'
              value={email}
              onChange={onCheckValidEmail}
            />
          </St.InputContainer>
          <StErrorMsg>
            {!isValidEmail && email.length > 0 && (
              <div>올바르지 않은 이메일 형식입니다.</div>
            )}
          </StErrorMsg>
          <St.InputContainer>
            <St.LoginInput
              type={isShowPw ? 'text' : 'password'}  // ⭐️⭐️ 아이콘 클릭시 input type 변경
              autoComplete='on'
              placeholder='비밀번호'
              value={pw}
              onChange={onCheckValidPw}
            />
            <St.PwIcon onClick={onShowPw}>
              {isShowPw ? <FiEye /> : <FiEyeOff />}	 // ⭐️⭐️ 비밀번호 표시/숨기기 아이콘
            </St.PwIcon>
          </St.InputContainer>
          <StErrorMsg>
            {!isValidPw && pw.length > 0 && (
              <div>영문, 숫자 포함 8자 이상 입력해주세요.</div>
            )}
          </StErrorMsg>
        </St.IdPwWrapper>
        <St.MemoWrapper>
          <St.CheckBox type='checkbox' />
          <St.MemoInfo>로그인 유지하기</St.MemoInfo>
        </St.MemoWrapper>
        <St.LoginBtn onClick={onLoginConfirm}>로그인</St.LoginBtn>
        <St.AskSignUpWrapper>
          <St.AskSignUp>아직 회원이 아니신가요?</St.AskSignUp>
          <St.SignUp onClick={onSignUpHandler}>회원가입</St.SignUp>
        </St.AskSignUpWrapper>
      </St.LoginWrapper>
    </>
  );
};

export default Login;


// ✅ css(styled-components)

// 모달창 닫기 버튼
export const CloseBtn = styled.button`
  position: absolute;
  width: 20px;
  height: 20px;
  top: 3%;
  right: 3%;
  padding: 0px;
  background-color: white;
  border: 1.5px solid ${colors.mainBlue};
  border-radius: 3px;
  color: ${colors.mainBlue};
  cursor: pointer;
`;

export const PwIcon = styled.div`
  position: absolute;
  width: 30px;
  top: 10%;
  right: 1%;
  cursor: pointer;
`;


리액트 아이콘 라이브러리(react-icons)

  • 리액트 아이콘 사이트 : https://react-icons.github.io/react-icons/
  • 사용 방법
    • npm install react-icons --save // npm
       yarn add react-icons // yarn
    • 원하는 아이콘 선택 후 Codes에서 그대로 복사하여 사용
      (아이콘 import & 코드 안에 컴포넌트로 넣기!)


🏹 트러블슈팅

  1. manifest syntax error
  • 에러 메시지 : manifest.json:1 Manifest: Line: 1, column: 1, Syntax error.
  • 해결 : index.html 에서
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
=> <link rel="/manifest" href="%PUBLIC_URL%/manifest.json" />

// '/'추가

  1. input type password 에러
  • 에러메시지 : [DOM] Input elements should have autocomplete attributes (suggested: "current-password"):

  • 해결

<StLoginInput type='password' />
=> <StLoginInput type='password' autoComplete='on' />
profile
꾸준히 성장하는 우상향 개발자

0개의 댓글