본문 바로가기
리액트 공부와 함께 하는 일상/3주차

[TIL] 3주차 - 2. 모달/주소 검색/state & prev

by fefe94 2022. 1. 26.

1. 경고창 모달로 변경하기

alert()를 대신 Modal을 이용해서 더 다양한 기능과 디자인으로 경고창을 만들 수 있습니다.

직접 구현할 수도 있고, ant-Design을 이용할 수도 있습니다.

 

 

https://ant.design/components/modal/

ant-Desing Modal 링크

 

https://mui.com/components/modal/#modal

material-UI Modal 링크

 

 

 

물론 prompt 사용할 수도 있긴 합니다.

Window.prompt() :  String prompt([String message], [String defaultValue])

Window.prompt()는 사용자가 텍스트를 입력할 수 있도록 안내하는 선택적 메시지를 갖고 있는 대화 상자입니다.

대화 상자는 modal window(부모 창으로 돌아가기 전에 사용자의 상호 작용을 요구하는 자식 창)로, 사용자는 대화 상자가 닫힐 때까지 나머지 모든 인터페이스에 접근할 수 없습니다. 따라서 대화 상자(또는 modal window)를 만드는 함수를 남용하면 안 됩니다.

문자열을 반환하기 때문에 필요시 타입 변환하여 사용하면 됩니다.

 

그런데

 

 

적은 내용이 다 보입니다. 댓글 삭제나 수정하기에서 prompt로 패스워드 입력 받을 시 보안 유출의 위험성이 있고 UI도 좀더 예쁘게 만들고 싶습니다. 

무엇보다 실무에서는 prompt를 사용하지 않습니다.

 

여튼 다시 Modal 내용으로 돌아가서.

ant-Design 으로 들어가서

 </> 를 클릭하면 아래에 코드가 나옵니다.

 

 

 

해당 코드를 가져가면 기본적인 Modal을 사용할 수 있는 것이고

추가적으로 필요한 내용과 스타일을 조절하면 됩니다.

 

ant-Design, material-ui에서 Modal을 사용하는 것 외에도

조건부 렌더링을 통해 직접 만들 수도 있습니다.

 

// import React, { useState } from 'react'; //순수 리액트 사용시 import 필요! 여기서는next 땜에 무필요
import { Modal, Button } from 'antd';
import { ChangeEvent, useState } from 'react';
// 내가 만드는 모달!!

export default function ModalCustomPage(){
  const [isModalVisible, setIsModalVisible] = useState(false);
  const [, setPassword] = useState("")

  const showModal = () => {
     // true 모달이 화면에 보인다.
    setIsModalVisible(true); 
  };

  const handleOk = () => {
    setIsModalVisible(false);
  };

  const handleCancel = () => {
    setIsModalVisible(false);
  };
  
  const onChangePassword = (event : ChangeEvent<HTMLInputElement>) => {
     setPassword(event.target.value)
  }
  // type="primary" ->  antd 에서 기본 파랑색 표현
  // html button으로 해도 된다.
  return (
    <>
      <Button type="primary" onClick={showModal}>
        Open Modal
      </Button>
      <Modal 
      title="나는 모달 제목이야" 
      visible={isModalVisible} 
      onOk={handleOk} 
      onCancel={handleCancel}
      >
        비밀번호 입력 : <input type="password" onChange={onChangePassword}/>
      </Modal>
    </>
  );
};

 

참고 )

Modal은 보통 다른 Tag들 보다 앞에 있어야 하기 때문에 position:absolute 속성을 주게 됩니다. 

 


 

 복습

조건부 렌더링 : 특정 조건에 따라 다른 결과물을 렌더링 하는 것을 의미합니다.

 

 


2. 주소 및 우편번호

 

주소를 검색하면 우편번호 및 번지 수, 도로명 주소를 알려주는 다양한 라이브러리가 있습니다. 그중 우리나라에서 가장 유명한 라이브러리를 사용해보겠습니다. (추후에 더 좋은 라이브러리가 나온다면 그걸 사용하면 좋겠지요.)

 

npm에서 react-daum-postcode 를 검색해서 설치 받기를 시작하면 됩니다.

https://www.npmjs.com/package/react-daum-postcode

 

설치는 아래 명령어로 해줍니다.

react-daum-postcode

 

DaumPostcode 속성을 이용하면 주소 검색 끝나고 자동으로 닫히게 할 수 있습니다.

(길이 조절, 애니메이션 등 다양한 속성들이 있습니다.)

 

// import React, { useState } from 'react'; //순수 리액트 사용시 import 필요! 여기서는next 땜에 무필요

import { Modal } from 'antd';
import { useState } from 'react';
import DaumPostcode from 'react-daum-postcode';


export default function ModalCustomPage(){
  const [isModalVisible, setIsModalVisible] = useState(false);
  const [address, setAddress] = useState("")
  const [zonecode, setZonecode] = useState("")

  // const showModal = () => {
  //   setIsModalVisible(prev => !prev); 
  // };

  // const handleOk = () => {nn
  //   setIsModalVisible(prev => !prev);
  // };

  // const handleCancel = () => {
  //   setIsModalVisible(prev => !prev);
  // };

  // 어차피 기존의 값을 반대로 만들어주는 논리라서 ! 활용함.
  

  const onToggleModal = () => {
    setIsModalVisible(prev => !prev);
  }
  
  // 대부분의 라이브러리는 타입 정해줌.
  const onCompleteDaumPostcode = (data : any) => {
    console.log(data);
    setAddress(data.address);
    setZonecode(data.zonecode);
    onToggleModal();
  }
  return (
    <>
      <button onClick={onToggleModal}>
        우편번호 검색
      </button>
      {isModalVisible && (
      <Modal visible={true} onOk={onToggleModal} onCancel={onToggleModal}>
        <DaumPostcode onComplete={onCompleteDaumPostcode}/>
      </Modal>
      )}
    </>
  );
};

 


3. state & prev

 

리액트 컴포넌트에서 다루는 데이터는

부모 컴포넌트가 자식 컴포넌트에게 데이터를 전달하는 props 와

컴포넌트 내부에서 선언하고 값 변경을 할 수 있는 state

이렇게 두개입니다.

(자식 컴포넌트에서는 props 를 받아오기만하고, 받아온 props 를 직접 수정 할 수 는 없습니다.)

 

import { useState } from "react"

export default function StatePrevPage(){
  const [count, setCount] = useState(0);

  const onClickCountUp = () => {
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
    // -> 이거 여러개 해도 1씩만 증가한다. 왜냐 임시저장소에 저장 되는 것이기 때문..

  }

  return(
    <>
      <div>현재 카운트 : {count}</div>
      <button onClick={onClickCountUp}>카운트 올리기!!</button>
    </>
  )
}

 

 위와 같은 코드에서

 setCount(counst + 1); 를 여러번 나열한다고

count 값이 나열한 수만큼 증가하지 않고 1씩만 증가합니다.

 

 

setCount를 했을 때 바로 count 값이 변하는게 아니라

임시 저장소에 저장되는 것이기 때문입니다.

 

즉, setCount(count + 1); 할 때 마다 계속 임시저장소에 새롭게

저장되고 있던 것입니다.

 

한번 카운트 버튼을 누를 때마다

여러번 증가되게끔 하고 싶다면 prev를 사용해야 합니다.

 

   setCount((prev) => (prev + 1));
    setCount((prev) => (prev + 1));
    setCount((prev) => (prev + 1));
    setCount((prev) => (prev + 1));
    // prev 임시 저장소에 있던 값을 꺼내온다. 없으면 기존의 값을 가져온다.

 

 위와 같은 코드로 바꿔주면

 

 

버튼 한번 클릭 때마다 4번씩 증가되는 것을 확인할 수 있습니다.

prev는 임시 저장소에 저장된 값을 가져오기 때문입니다.

 

이 때, 만약 임시 저장소에 값이 없다면

기존의 값을 가져오게 됩니다. 

 


 

import { useState } from "react"

export default function StatePrevPage(){
  const [count, setCount] = useState(0);

  const onClickCountUp = () => {
    setCount(count=> count++);
  }

  return(
    <>
      <div>현재 카운트 : {count}</div>
      <button onClick={onClickCountUp}>카운트 올리기!!</button>
    </>
  )
}

 

이 때

setCount(count=> count++); 라고 해두면
아예 버튼 클릭 시 증가 자체가 안되는데
그 이유는..
애초에 count를 const 상수 타입으로 선언했기 때문입니다.
 
 

Reference

https://developer.mozilla.org/ko/docs/Web/API/Window/prompt 

 

Window.prompt() - Web API | MDN

Window.prompt()는 사용자가 텍스트를 입력할 수 있도록 안내하는 선택적 메세지를 갖고 있는 대화 상자를 띄웁니다.

developer.mozilla.org

 

댓글