1. Props란 무엇인가?
리액트(React)에서 Props(Properties의 줄임말)는 부모 컴포넌트가 자식 컴포넌트로 데이터를 전달하는 방법입니다. 쉽게 말해, Props는 컴포넌트 간에 정보를 전달하는 통로입니다.
1.1 Props의 특성
Props의 가장 중요한 특성은 읽기 전용(Read-only)이라는 점입니다. 자식 컴포넌트는 자신이 받은 Props를 직접 수정할 수 없습니다. 이것은 마치 함수의 매개변수와 비슷합니다 - 함수 내부에서 전달받은 인자의 값을 직접 변경하지 않는 것과 같은 원리입니다.
1.2 Props 사용 예시
아래 예시를 통해 Props가 어떻게 사용되는지 살펴보겠습니다:
// 부모 컴포넌트
function ParentComponent() {
return (
<ChildComponent name="React" color="blue" />
);
}
// 자식 컴포넌트
function ChildComponent(props) {
return (
<div style={{ color: props.color }}>
안녕하세요, {props.name}!
</div>
);
}
위 예시에서 부모 컴포넌트는 name과 color라는 두 가지 Props를 자식 컴포넌트에 전달하고 있습니다. 자식 컴포넌트는 이 Props를 사용하여 화면에 "안녕하세요, React!"라는 메시지를 파란색으로 표시합니다.
2. State란 무엇인가?
State는 컴포넌트 내부에서 관리되는 데이터입니다. Props가 외부에서 받는 데이터라면, State는 컴포넌트 자신이 소유하고 관리하는 데이터입니다.
2.1 State의 특성
State의 주요 특성은 다음과 같습니다:
- 컴포넌트 내부에서 선언되고 관리됩니다.
- 동적으로 변경될 수 있습니다.
- State가 변경되면 컴포넌트가 다시 렌더링됩니다.
- 주로 사용자 입력이나 API 응답과 같이 시간에 따라 변할 수 있는 데이터를 관리합니다.
2.2 State 사용 예시
다음은 클릭할 때마다 카운터가 증가하는 간단한 예시입니다:
import React, { useState } from 'react';
function Counter() {
// count는 상태 변수, setCount는 해당 상태를 변경하는 함수
const [count, setCount] = useState(0);
return (
<div>
<p>현재 카운트: {count}</p>
<button onClick={() => setCount(count + 1)}>
증가
</button>
</div>
);
}
이 예시에서 count는 State로, 초기값은 0입니다. 버튼을 클릭하면 setCount 함수를 호출하여 count 값을 증가시킵니다. State가 변경되면 컴포넌트가 다시 렌더링되어 업데이트된 카운트 값이 화면에 표시됩니다.
3. Props가 자식 컴포넌트에서 변하지 않는 이유
Props가 자식 컴포넌트에서 변경되지 않는 이유는 리액트의 단방향 데이터 흐름 원칙 때문입니다.
3.1 단방향 데이터 흐름의 중요성
리액트의 단방향 데이터 흐름은 다음과 같은 장점을 제공합니다:
- 예측 가능성: 데이터가 한 방향으로만 흐르기 때문에, 애플리케이션의 상태 변화를 추적하고 이해하기 쉽습니다.
- 디버깅 용이성: 문제가 발생했을 때, 데이터의 변화를 추적하기 쉽습니다.
- 컴포넌트 재사용성: Props가 불변이면, 컴포넌트는 외부 입력에만 의존하게 되어 재사용이 쉬워집니다.
만약 자식 컴포넌트가 Props를 직접 수정할 수 있다면, 다음과 같은 문제가 발생할 수 있습니다:
// 잘못된 예시
function ChildComponent(props) {
props.name = "새 이름"; // 오류 발생 가능!
return <div>{props.name}</div>;
}
이런 코드는 Props의 불변성 원칙을 위반하며, 리액트의 단방향 데이터 흐름을 해치게 됩니다.
4. 자식 컴포넌트에서 Props를 변경해야 할 때
그렇다면, 자식 컴포넌트에서 부모로부터 받은 데이터를 변경해야 할 필요가 있다면 어떻게 해야 할까요?
4.1 상태 끌어올리기 패턴
리액트에서는 이런 상황을 상태 끌어올리기(Lifting State Up) 패턴을 통해 해결합니다. 데이터를 변경해야 하는 컴포넌트들의 가장 가까운 공통 부모 컴포넌트에서 상태를 관리하고, 상태 변경 함수를 Props로 전달하는 방식입니다.
4.2 실제 구현 예시
예를 들어, 사용자 이름을 표시하고 수정할 수 있는 컴포넌트를 구현해 보겠습니다:
import React, { useState } from 'react';
// 부모 컴포넌트
function UserProfile() {
// 상태를 부모 컴포넌트에서 관리
const [userName, setUserName] = useState("초기 사용자명");
// 상태 변경 함수를 자식 컴포넌트에 전달
return (
<div>
<h2>사용자 프로필</h2>
<UserNameDisplay name={userName} />
<UserNameEditor name={userName} onNameChange={setUserName} />
</div>
);
}
// 이름을 표시하는 컴포넌트
function UserNameDisplay({ name }) {
return <p>현재 사용자: {name}</p>;
}
// 이름을 수정하는 컴포넌트
function UserNameEditor({ name, onNameChange }) {
return (
<div>
<input
value={name}
onChange={(e) => onNameChange(e.target.value)}
/>
<button onClick={() => onNameChange("기본 이름")}>
기본값으로 초기화
</button>
</div>
);
}
이 예시에서:
- UserProfile 컴포넌트는 userName 상태와 이를 변경하는 setUserName 함수를 가지고 있습니다.
- UserNameDisplay 컴포넌트는 이름을 표시하기만 합니다.
- UserNameEditor 컴포넌트는 이름을 수정할 수 있지만, 직접 Props를 수정하는 대신 부모로부터 받은 onNameChange 함수를 호출하여 변경을 요청합니다.
이렇게 하면 데이터 흐름은 여전히 단방향으로 유지되면서도, 자식 컴포넌트에서 부모 컴포넌트의 상태를 간접적으로 변경할 수 있습니다.
5. Props와 State의 효과적인 사용법
Props와 State를 효과적으로 사용하기 위한 몇 가지 팁은 다음과 같습니다:
- Props는 설정값으로 생각하세요: Props는 컴포넌트의 설정이나 구성으로 생각하면 좋습니다. 컴포넌트가 어떻게 보여질지, 어떻게 동작할지를 결정합니다.
- 상태는 최소한으로 유지하세요: 꼭 필요한 데이터만 State로 관리하고, 가능한 한 적은 상태를 유지하는 것이 좋습니다.
- 상태는 적절한 위치에 배치하세요: 특정 State를 필요로 하는 모든 컴포넌트의 가장 가까운 공통 조상에 해당 State를 배치하세요.
- 파생된 값은 계산하세요: State에서 계산할 수 있는 값은 별도의 State로 관리하지 말고, 렌더링 과정에서 계산하세요.
// 좋은 예시
function Temperature({ celsius }) {
// 화씨 온도는 섭씨 온도에서 계산됨
const fahrenheit = (celsius * 9/5) + 32;
return (
<div>
<p>섭씨: {celsius}°C</p>
<p>화씨: {fahrenheit}°F</p>
</div>
);
}
이렇게 Props와 State를 적절히 활용하면, 더 예측 가능하고 관리하기 쉬운 리액트 애플리케이션을 만들 수 있습니다.
Props와 State는 리액트의 기본 개념이지만, 이를 제대로 이해하고 활용하는 것은 효과적인 컴포넌트 설계의 핵심입니다. 컴포넌트가 복잡해질수록 데이터 흐름을 명확하게 유지하는 것이 중요하며, 이를 위해 단방향 데이터 흐름 원칙을 잘 준수해야 합니다.
'1일 1CS(Computer Science)' 카테고리의 다른 글
데이터베이스 인덱스에 대해서 설명해주세요. (0) | 2025.04.03 |
---|---|
리액트의 Controlled Component와 Uncontrolled Component (0) | 2025.04.03 |
이벤트 루프에 대해서 설명해주세요. (0) | 2025.03.28 |
TanStack Query: staleTime과 gcTime (0) | 2025.03.27 |
reflow와 repaint의 차이점과 최적화 방법 (1) | 2025.03.26 |