State & Props
React에서 데이터를 다룰 때 가장 기본이 되는 개념은 State와 Props다.
State는 컴포넌트 내부에서 관리하는 데이터Props는 부모 컴포넌트가 자식 컴포넌트에게 전달하는 데이터
State
State는 컴포넌트 내부에서 관리되는 변경 가능한 데이터다.
사용자의 클릭, 입력값, 토글 상태처럼 화면에서 변경될 수 있는 값을 관리할 때 사용한다.
State 값이 변경되면 React는 해당 컴포넌트를 다시 렌더링해 화면을 업데이트한다.
- 컴포넌트가 현재 가지고 있는 값
- 사용자 행동에 따라 변경될 수 있는 동적인 데이터
- 값이 변경되면 화면 업데이트를 발생시키는 데이터
useState Hook
React 함수형 컴포넌트에서는 useState Hook을 사용해 State를 관리한다.useState()를 호출하면 두 개의 요소가 들어있는 배열이 반환된다.
const state = useState();
console.log(state); // [undefined, ƒ]useState()에 초기값을 전달하지 않으면 첫 번째 값은undefined가 된다.- 두 번째 값은
State값을 변경할 때 사용하는 함수다.
[현재 상태 값, 상태 변경 함수]- 반환값은 다음과 같은 구조를 가진다. 그래서 보통 배열 구조 분해 할당을 사용해 다음과 같이 작성한다.
const [state, setState] = useState(initialValue);state: 현재 상태 값setState: 상태를 변경하는 함수initialValue: state의 초기값
// ex
const [isLogin, setIsLogin] = useState(false);ex. 로그인 여부를 상태로 관리한다면,
처음에는 로그인하지 않은 상태이므로 false를 초기값으로 설정하고, 로그인 후에는 setIsLogin(true)처럼 상태를 변경할 수 있다.
State를 사용할 때 주의할 점
State는 직접 수정하지 않고, 반드시 상태 변경 함수를 사용해야 한다.
const [user, setUser] = useState({ name: "짱구", age: 5 });
// 잘못된 예시
user.age = 6;
// 올바른 예시
setUser({ ...user, age: 6 });React는 상태 변경 함수를 통해 값이 바뀌었는지 감지하고, 필요한 경우 화면을 다시 렌더링한다.
따라서 State를 직접 수정하면 React가 변경을 제대로 감지하지 못할 수 있다.
setCount((prevCount) => prevCount + 1);또한 이전 상태값을 기준으로 값을 업데이트해야 할 때는 함수형 업데이트 방식을 사용할 수 있다.
이 방식은 이전 상태값을 안전하게 참조할 수 있기 때문에, 연속적인 상태 변경이 필요한 경우에 유용하다.
🤔 일반 변수가 아닌 State를 사용하는 이유
일반 변수는 값이 변경되어도 React가 그 변화를 감지하지 못하기 때문에 화면이 다시 렌더링되지 않는다.
반면 State는 상태 변경 함수로 값이 변경되면 React가 이를 감지하고 컴포넌트를 다시 렌더링해 변경된 값을 화면에 반영한다.
Props
Props는 부모 컴포넌트가 자식 컴포넌트에게 전달하는 데이터다. 컴포넌트는 Props를 통해 외부에서 값을 전달받고, 전달받은 값을 화면에 표시하거나 로직에 사용할 수 있다.
ex. UserProfile 컴포넌트에 사용자 이름을 전달해보면,
function UserProfile({ name }) {
return <p>안녕하세요, {name}님!</p>;
}
function App() {
return <UserProfile name="짱구" />;
}
export default App;- App 컴포넌트는 UserProfile 컴포넌트에게 name이라는 Props를 전달
- UserProfile 컴포넌트는 전달받은 name 값을 사용해 화면에 문장을 출력
Props의 특징
Props는 부모 컴포넌트에서 자식 컴포넌트로 전달
즉, 데이터 흐름은 기본적으로 위에서 아래 방향으로 흐른다.Props는 자식 컴포넌트에서 직접 수정하지 않는다
자식 컴포넌트는 전달받은 Props를 읽어서 사용할 수 있지만, 그 값을 직접 변경해서는 안 된다.
function UserProfile({ name }) {
// name = "훈이"; // 직접 수정하면 안 됨
return <p>{name}</p>;
}- Props 값을 변경해야 한다면, 해당 값을 관리하는 부모 컴포넌트에서 State를 변경한 뒤 다시 Props로 전달해야 한다.
State를 Props로 전달하기
State와 Props는 따로 사용되기도 하지만, 함께 사용되는 경우가 많다.
대표적으로 부모 컴포넌트에서 State를 관리하고, 그 State 값을 자식 컴포넌트에게 Props로 전달하는 방식이다. 부모의 State가 변경되면 변경된 값이 다시 자식 컴포넌트의 Props로 전달되고, 화면도 함께 업데이트된다.
import { useState } from "react";
import Bulb from "./Bulb";
function App() {
const [light, setLight] = useState("OFF");
return (
<>
<Bulb light={light} />
<button
onClick={() => {
setLight(light === "ON" ? "OFF" : "ON");
}}
>
{light === "ON" ? "끄기" : "켜기"}
</button>
</>
);
}
export default App;const Bulb = ({ light }) => {
return (
<div>
{light === "ON" ? (
<h1 style={{ backgroundColor: "orange" }}>ON</h1>
) : (
<h1 style={{ backgroundColor: "gray" }}>OFF</h1>
)}
</div>
);
};
export default Bulb;App컴포넌트는lightState를 관리하고, 이 값을Bulb컴포넌트에게lightProps로 전달한다.- 버튼을 클릭하면
setLight를 통해light값이"ON"또는"OFF"로 변경된다. - State가 변경되면
App컴포넌트가 리렌더링되고, 변경된light값이 다시Bulb의 Props로 전달된다. - 그 결과
Bulb는 전달받은light값에 따라 ON/OFF 화면을 다르게 보여준다.
리렌더링
React 컴포넌트는 특정 값이 변경되었을 때 다시 렌더링된다. 이를 리렌더링이라고 한다.
- 컴포넌트가 관리하는
State값이 변경될 때 - 부모 컴포넌트로부터 전달받는
Props값이 변경될 때 - 부모 컴포넌트가 리렌더링될 때
위 예시에서는 버튼 클릭으로
lightState가 변경되고,
이 값이Bulb컴포넌트의 Props로 다시 전달되면서 화면이 업데이트된다.