상황은 이렇다.
부모 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 />}
동작 원리
- FindIdContent 안에서 버튼을 누르면,
handleClickFindPw() 함수가 실행되고
setModalContentType('findPwType') 으로 상태가 변경된다. - 상태가 변경되면, React는 부모 컴포넌트 Login을 다시 렌더링한다.
- 렌더링 과정에서 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 타입 미리 정의하고 함수 파라미터에 적용하면 깔끔해요!
필요하면 타입스크립트 함수 타입 관련 예시 더 드릴까요?
'Studying > React' 카테고리의 다른 글
리액트 공부하기 - 스타일 캡슐화 (부모 컴포넌트 영향 안받고 자식 컴포넌트 디자인..) (0) | 2025.07.05 |
---|---|
리액트 공부하기 - hook-form 훅폼 사용시 disabled 지정해야할까? 고민 (1) | 2025.07.02 |
리액트 공부하기 - 모달 만들기 (0) | 2025.06.28 |
리액트 공부하기 - hook form (0) | 2025.06.24 |
리액트 - input은 문자열 (1) | 2025.06.24 |