State
리액트 컴포넌트의 상태를 의미함, 즉 리액트 컴포넌트의 변경 가능한 데이터
state는 자바스크립트 객체임
state는 사전에 미리 정해진 것이 아니므로 컴포넌트를 개발하는 개발자가 직접 정의해서 사용함
렌더링이나 데이터 흐름에 사용되는 값만 state에 포함시켜야 함
- 왜냐하면 state가 변경될 경우 컴포넌트가 다시 렌더링 되기 때문에 렌더링과 데이터 흐름에 관련 없는 값을 포함하면, 컴포넌트가 다시 렌더링 되어 성능을 저하 시킬 수 있기 때문
import React, { useState } from 'react';
const WrongExample = () => {
const [name, setName] = useState('나마니');
const [count, setCount] = useState(0);
const [unusedValue, setUnusedValue] = useState('이 값은 렌더링과 관계없음');
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>{name}</p>
<p>{count}</p>
<button onClick={increment}>Increase Count</button>
</div>
);
};
export default WrongExample;
`unusedValue`는 `state` 에 포함되어 있지만 렌더링에 영향을 주지 않으므로 결과에 나타나지 않음.
결과
처음 결과
<div>
<p>나마니</p>
<p>0</p>
<button>Increase Count</button>
</div>
이후 `Increase Count` 버튼을 누르면 `count` 값이 1씩 증가됨 다시 렌더링이 됨
<div>
<p>나마니</p>
<p>1</p>
<button>Increase Count</button>
</div>
해당 값은 컴포넌트의 성능에 부정적인 영향을 줄 수 있으므로 불필요하게 `state` 에 포함시키지 말 것
올바른 결과
import React, { useState } from 'react';
const CorrectExample = () => {
const [name, setName] = useState('나마니');
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>{name}</p>
<p>{count}</p>
<button onClick={increment}>Increase Count</button>
</div>
);
};
export default CorrectExample;
여기서는 `name`과 `count`만 `state`로 관리하고 있고, 두 값 모두 렌더링에 사용되므로 `state`에 포함시키는 것이 많음
만약 컴포넌트에 사용되지 않는 데이터를 관리해야 한다면, 그 값을 단순한 변수로 두는 것이 좋다.
그렇게 하면 불필요한 렌더링을 피할 수 있다.
state의 특징
모든 클래스 컴포넌트에는 `constructor`라는 이름의 함수가 존재한다.
class LikeButton extends React.Component {
constructor(props) {
super(props);
this.state = {
liked: false
};
}
}
위 코드에서 `this.state`라는 부분이 나오는데 이 부분이 바로 현재 컴포넌트의 state를 정의하는 부분이다.
클래스 컴포넌트의 경우 `state`를 생성자에서 정의하고, 함수 컴포넌트는 `state`를 `useState()`라는 훅을 사용해서 정의한다.
`state`는 정의된 이후 직접적인 변경이 불가능하다. (`setState()` 함수를 통해 수정해야 함)
생명주기
Lifecycle method, 생명주기 함수
Mounting (출생)
컴포넌트가 생성되는 시점, 이 과정을 `Mount (마운트)` 라고 한다.
이때 컴포넌트의 `constructor(생성자)` 가 실행된다. 생성자에서는 컴포넌트의 state를 정의하게 된다.
또한 컴포넌트가 렌더링되며 이후에 `componentDidMount()` 함수가 호출된다.
Rendering(렌더링): 컴포넌트의 props와 state의 상태에 기초하여 UI를 어떻게 구성할지 컴포넌트에게 요청하는 작업, 쉽게 말해 해당 컴포넌트를 다시 실행한다고 생각하면 된다.
렌더링이 발생하면 선언부에서 초기화 한 값으로 변경되고, 렌더링의 발생 조건은 컴포넌트가 가지고 있는 값이 변경될 때이다. 그래서 `state`를 사용해야하고, 그 외에 다른 것들은 값이 고정되어 있어야 한다. (리액트의 순수성)
렌더링이 왜 필요한가?
1. UI 상태 관리의 복잡성 해결: 전통적인 방법으로는 DOM을 직접 조작하면서 모든 변경사항을 관리해야 함
2. 가상 DOM: 가상 DOM은 실제 DOM의 가벼운 복사본으로, 상태 변화가 있을 때마다 새 가상 DOM을 생성하고 이전 가상 DOM과 비교하여 실제 DOM을 최소한으로 업데이트 한다. (참고: https://namaniflow.tistory.com/292)
3. 컴포넌트 기반 아키텍처: 리액트는 UI를 재사용 가능한 컴포넌트로 분리해서 개발할 수 있게 하는데, 각 컴포넌트는 독립적인 상태와 렌더링 로직을 갖고 있다. 때문에 변경이 필요한 부분만 업데이트 되도록 한다.
4. 데이터 흐름과 상태 관리: 리액트는 단방향 데이터 흐름을 지향한다. 즉, 상태가 변경되면 그 상태를 기반으로 컴포넌트를 다시 렌더링하여 UI를 업데이트 한다. state와 UI가 항상 일치하게 유지된다.
5. 성능 최적화: 가상 DOM을 통해 불필요한 DOM 업데이트를 피하고, 최적의 방법으로 UI 업데이트 가능하다.
Updating
컴포넌트의 props가 변경되거나 setState() 함수 호출에 의해 state가 변경되거나, forceUpdate()라는 강제 업데이트 함수 호출로 인해 컴포넌트가 다시 렌더링 된다.
렌더링 이후에 `componentDidUpdate()` 함수가 호출 된다.
Unmount(언마운트)
상위 컴포넌트에서 현재 컴포넌트를 더 이상 화면에 표시하지 않게 될 때 언마운트 된다.
언마운트 직전에 `componentWillUnmount()` 함수가 호출 된다.
참고
'TIL > React' 카테고리의 다른 글
[TIL/React] BrowserRouter, Navigation, Routes, Route (0) | 2024.07.30 |
---|---|
[TIL/React] Hooks, useState, useEffect (0) | 2024.07.24 |
[TIL/React] 리액트 컴포넌트, Props (0) | 2024.07.21 |
[TIL/React] 리액트 엘리먼트, DOM 엘리먼트 (0) | 2024.07.20 |
[TIL/React] 리액트 앱의 실행 순서와 컴포넌트 (0) | 2024.07.16 |