귀여운 눈높이에서 작성된, 🐰

하루 한 걸음씩, 성장 하는 중 입니다 🫶🏻

Studying/React

리액트 공부하기 - 상태 useState에서, setter 를 Props로 내려주기, 타입 지정하기 (부모 컴포넌트에서, 자식 컴포넌트로 상태를 props로 전달할 경우)

creamymood 2025. 7. 1. 20:32

 

초 집 중. 요즘 프로젝트 하는 나..

 

 

상황은 이렇다.

 

부모 Login 컴포넌트의 모달에서,

모달에 어떤 화면을 보여줄지를 정하는 상태가 있는데 (아이디 설정 내용 ? 비밀번호 설정 내용 ? )

const [modalContentType, setModalContentType] = useState<
    'findIdType' | 'findPwType'
  >('findIdType') //모달에 어떤  찾기 화면 보여줄지 상태(아이디찾기, 비밀번호 찾기)

 

여기서 

 <button
            onClick={() => {
              setIsModalOpen(true)
              setModalContentType('findIdType')
            }}
            className="mr-[8px]"
          >
            아이디 찾기
          </button>
          {isModalOpen && (
            <FindModal onClose={() => setIsModalOpen(false)}>
              {modalContentType === 'findIdType' && (
                <FindIdContent setModalContentType={setModalContentType} />
              )}
              {modalContentType === 'findPwType' && <FindPwContent />}
            </FindModal>
          )}

          <p className="mr-[8px]">|</p>

          <button
            onClick={() => {
              setIsModalOpen(true)
              setModalContentType('findPwType')
            }}
          >
            비밀번호 찾기
          </button>

이런식으로 쓰이는 코드다.

 

즉, 모달내용이 findIdType이면, 아이디 찾기 컴포넌트를 보여주고,

                       findPwType이면, 비밀번호 찾기 컴포넌트를 보여주는 흐름이다.

 

 

<FindIdContent setModalContentType={setModalContentType} />

이 때, 아이디 찾기 컴포넌트에, 이와 관련된 상태를 내려주고 있는데 그 이유는

 

아이디 찾기 컴포넌트에서도, 비밀번호 찾기 화면으로의 전환이 필요하기 때문이다.

 

이 때, 코드는 다음과 같다.

<button
              className="h-[48px] w-[168px] rounded-[4px] bg-[#6201E0] text-[16px] font-semibold text-[#FAFAFA]"
              onClick={handleClickFindPw}
            >
              비밀번호 찾기
            </button>

비밀번호 찾기! 를 누르면, handleClickFinePw 함수가 실행이 되는데, 그 함수는 바로 상태를 findPwType으로 바꿔주는 함수다

//누르면, 비밀번호 찾기 화면 상태로 바꾸는 함수
  const handleClickFindPw = () => {
    setModalContentType('findPwType')
  }

 

부모 요소인 Login에 렌더링 관련된 로직은 이미 그려놨다.

자식 요소인 FindIdContent에서 비밀번호 내용 보여줘~ 라고 상태 바꿨으니 부모에서 렌더링 되는 것.

{/*모달이 열릴 때, 모달컨텐트 타입이, findIdType이면 아이디찾기 내용 보여주기 / findPwContent면 비밀번호 찾기 내용 보여주기 렌더링 관련 */}

          {isModalOpen && (
            <FindModal onClose={() => setIsModalOpen(false)}>
              {modalContentType === 'findIdType' && (
                <FindIdContent setModalContentType={setModalContentType} />
              )}
              {modalContentType === 'findPwType' && <FindPwContent />}
            </FindModal>
          )}

 

아래는 위 상황에 대한 간단한 설명을 덧붙였다.

더보기

상황 정리

  • Login 부모 컴포넌트에는 modalContentType 상태가 있다.
    이 상태는 모달에 어떤 내용을 보여줄지 결정한다.
    'findIdType' 이면 아이디 찾기 화면
    'findPwType' 이면 비밀번호 찾기 화면
  • 모달 안에서 조건부 렌더링을 한다.
{modalContentType === 'findIdType' && <FindIdContent setModalContentType={setModalContentType} />}
{modalContentType === 'findPwType' && <FindPwContent />}

 

동작 원리

  1. FindIdContent 안에서 버튼을 누르면,
    handleClickFindPw() 함수가 실행되고
    setModalContentType('findPwType') 으로 상태가 변경된다.
  2. 상태가 변경되면, React는 부모 컴포넌트 Login을 다시 렌더링한다.
  3. 렌더링 과정에서 modalContentType 값이 'findPwType' 이므로,
    조건부 렌더링에 따라 <FindPwContent /> 컴포넌트가 화면에 나타난다.

핵심

  • modalContentType 상태가 모달 안에서 보여줄 화면을 결정하고
  • 상태가 바뀌면 React가 자동으로 렌더를 다시 해서
  • 그에 맞는 화면(컴포넌트)을 보여준다.

따라서 FindIdContent 내부에서 상태를 바꾸면,
그 상태 변화에 맞춰 부모 컴포넌트가 다시 렌더링되면서
다른 화면(FindPwContent)이 자연스럽게 렌더된다!


이까지는 흐름이었고, 내가 공부하고 싶은 부분은 이거다.

부모요소의 상태를, 자식에 내려줄 때 그 "setter"

즉, 

const [example, setExample] = useState('')

여기서, setExample 저 상태 바꾸는 함수를 내리고 싶을 때, 

 

그냥 냅다, 다른 프롭스 처럼 

FindModal({ onClose, children})

이게 아니더라..

 

+ js는 괜찮은데, 타입스크립트 타입 지정 부분이 공부해야 했음!

더보기

1️⃣ JSX에서 props로 setter 함수 내려주는 법 (간단히)

<Child setText={setText} />
  • 여기서 setText는 부모 컴포넌트에서 만든 상태를 바꾸는 함수예요.
  • 이걸 props 이름 setText로 자식 컴포넌트에 그냥 전달하는 거예요.
  • 자식은 props로 받은 setText를 그냥 함수처럼 쓰면 됩니다!

2️⃣ 자식 컴포넌트에서 이 함수 받는 법

function Child({ setText }) {
  // setText라는 함수가 props로 들어왔어요
  // 예를 들어, input에서 글자가 바뀌면 이걸 호출해서 부모 상태를 바꿀 수 있어요.
  return (
    <input
      type="text"
      onChange={(e) => setText(e.target.value)} // 부모 상태 바꾸기
    />
  );
}

3️⃣ TypeScript 쓸 때 타입 지정 쉽게 하기

interface ChildProps {
  setText: (value: string) => void;
}
  • 여기서 setText는 문자열 하나 받아서 반환값 없는 함수라고 쉽게 생각하면 돼요.
  • 복잡한 타입표현 안 해도 돼요!
  • 그래서 자식 컴포넌트 선언할 때 이렇게 쓸 수 있죠:
function Child({ setText }: ChildProps) {
  ...
}

한 줄 요약

  • 부모가 setText 함수를 만들어서 자식에게 준다 → 자식이 이걸 호출해서 부모 상태를 바꾼다!
  • TypeScript로 쓸 때도 너무 복잡하게 생각하지 말고,
    그냥 (value: string) => void 형태의 함수라고 생각하면 편해요!

이런 느낌이라는 건데...

 

그러면, 이런 느낌이란건가? 했더니

type FindIdContentProps : {
setModalcontentType : ()=> void}

export default function FindIdContent({
  setModalContentType,
} : FindIdContentProps)

거의 근접!

 

주의할 점!

인자가 있으면, 인자도 같이 적어줘야 한다.

더보기

아주 좋아요! 👍

말씀하신 방법도 완전히 맞고, 오히려 더 간결해서 많이 쓰이는 스타일이에요.


차이점과 장점 정리해 드릴게요

type FindIdContentProps = {
  setModalContentType: () => void
}

export default function FindIdContent({
  setModalContentType,
}: FindIdContentProps) {
  // ...
}
  • type으로 props 타입을 미리 선언해 두고
  • 함수 파라미터에서 그 타입을 사용해서 간결하게 쓰는 방법이에요.
  • () => void는 "인자 없고 반환값 없는 함수"라는 뜻인데,
    만약 setModalContentType이 인자를 받는다면 타입을 조금 바꿔야 해요.

그런데 setModalContentType이 인자를 받는다면?

type FindIdContentProps = {
  setModalContentType: (value: 'findIdType' | 'findPwType') => void
}

이렇게 해야 정확합니다.

type FindIdContentProps = {
  setModalContentType: (value: 'findIdType' | 'findPwType') => void
}

export default function FindIdContent({
  setModalContentType,
}: FindIdContentProps) {
  const handleClickFindPw = () => {
    setModalContentType('findPwType')
  }

  return <button onClick={handleClickFindPw}>비밀번호 찾기</button>
}

 

  • () => void는 인자가 없는 함수 타입이에요.
  • setModalContentType은 인자를 받기 때문에 (value: 'findIdType' | 'findPwType') => void 이렇게 타입 써주세요.
  • type으로 props 타입 미리 정의하고 함수 파라미터에 적용하면 깔끔해요!

필요하면 타입스크립트 함수 타입 관련 예시 더 드릴까요?