- 발행일
[ZBF] REACT 멘토링 준비
[ZBF] REACT 멘토링 준비
이 글은 네이버 블로그에 2024년 6월 9일에 올렸던 것을 그대로 옮겨온 것입니다.
DOM에 대해 설명해 주세요.
DOM은 Document Object Model의 약자로, HTML, XML 문서의 구조화된 표현을 말합니다. DOM은 문서를 트리 구조로 표현하며, 각각의 노드는 문서의 일부를 나타냅니다.
- 기본 개념: DOM은 문서의 구조를 프로그래밍 언어에서 사용할 수 있도록 해주는 인터페이스입니다. 웹 브라우저는 HTML 문서를 로드할 때 DOM을 생성하고, 이를 통해 자바스크립트와 같은 스크립트 언어가 문서의 내용을 동적으로 조작할 수 있게 합니다.
2. 구성 요소:
- 노드: DOM 트리의 기본 단위로, 각 노드는 문서의 요소(태그), 속성, 텍스트 등을 나타냅니다.
- 요소 노드: HTML 태그를 나타내며, 다른 노드를 자식으로 가질 수 있습니다.
- 텍스트 노드: 요소 노드의 자식으로, 텍스트 콘텐츠를 포함합니다.
- 속성 노드: 요소 노드의 속성을 나타냅니다.
3. 조작 방법:
- 탐색: document.getElementById, document.querySelector 등을 사용해 DOM 요소를 탐색할 수 있습니다.
- 수정: element.innerHTML, element.setAttribute 등을 사용해 DOM 요소를 수정할 수 있습니다.
- 이벤트 처리: element.addEventListener를 사용해 사용자 인터랙션에 반응할 수 있습니다.
// ID가 'myElement'인 요소를 찾아 텍스트를 변경하는 예제
const element = document.getElementById('myElement');
element.textContent = 'Hello, World!';
Virtual DOM에 대해 설명해 주세요.
Virtual DOM은 실제 DOM(Document Object Model)의 추상적인 복사본으로, DOM 조작을 최적화하기 위해 사용됩니다. Virtual DOM은 React와 같은 프레임워크에서 주로 사용되며, 다음과 같은 특징이 있습니다.
- 기본 개념:
- Virtual DOM: 실제 DOM의 경량화된 복사본입니다. 메모리 내에 존재하며, 실제 DOM과 동기화됩니다.
- 효율성: DOM 조작은 비용이 많이 드는 작업입니다. Virtual DOM을 사용하면, 변경된 부분만 실제 DOM에 반영하기 때문에 성능이 향상됩니다.
- 작동 방식:
- 초기 렌더링: 컴포넌트가 처음 렌더링될 때, Virtual DOM 트리가 생성됩니다.
- 업데이트: 상태(state)나 속성(props)이 변경되면, 새로운 Virtual DOM 트리가 생성됩니다.
- 비교: 이전 Virtual DOM 트리와 새로운 트리를 비교하여, 변경된 부분만 추적합니다. 이 과정을 "diffing"이라고 합니다.
- 패치: 변경된 부분만 실제 DOM에 반영합니다. 이를 통해 불필요한 DOM 업데이트를 줄여 성능을 최적화합니다.
3. 장점:
- 성능 최적화: 변경된 부분만 업데이트하므로 DOM 조작이 최적화됩니다.
- 프레임워크 활용: React와 같은 프레임워크는 Virtual DOM을 사용하여 컴포넌트 기반의 효율적인 UI 업데이트를 제공합니다.
// React의 예제 코드
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>{this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
Virtual DOM이 실제 DOM보다 효율적인 이유
1. 비교와 최소 업데이트:
Virtual DOM은 메모리에서 DOM의 가상 표현을 유지하고, 상태 변경 시 변경된 부분만 비교(diffing)하여 실제 DOM에 필요한 최소한의 업데이트만 수행합니다.
이를 통해 불필요한 DOM 조작을 줄이고, 브라우저의 렌더링 비용을 절감할 수 있습니다.
2. 배치된 업데이트:
Virtual DOM을 사용하면 여러 변경 사항을 모아서 한 번에 적용할 수 있습니다. 이는 브라우저가 여러 번의 작은 업데이트 대신 한 번의 큰 업데이트를 처리하게 하여, 효율성을 높입니다.
3. 추상화된 인터페이스:
Virtual DOM은 브라우저의 세부 구현에 종속되지 않는 추상화된 인터페이스를 제공하여, 코드의 일관성과 유지보수성을 높입니다.
이를 통해 개발자는 복잡한 DOM 조작을 직접 관리할 필요 없이, 더 간단하고 일관된 코드를 작성할 수 있습니다.
클래스형 컴포넌트와 함수형 컴포넌트의 차이를 설명해 주세요.
React에서 컴포넌트를 정의하는 두 가지 방법인 클래스형 컴포넌트와 함수형 컴포넌트는 각각의 장단점과 특징이 있습니다.
- 클래스형 컴포넌트:
- 정의 방법: 클래스를 사용하여 정의합니다. React.Component를 상속받아야 합니다.
- 상태 관리: state 객체를 사용하여 컴포넌트의 상태를 관리합니다.
- 생명 주기 메서드: componentDidMount, componentDidUpdate, componentWillUnmount 등과 같은 생명 주기 메서드를 사용할 수 있습니다.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
componentDidMount() {
// 컴포넌트가 마운트된 후 실행
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>{this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
2. 함수형 컴포넌트:
- 정의 방법: 함수를 사용하여 정의합니다. 주로 화살표 함수를 사용합니다.
- 상태 관리 및 생명 주기 관리: useState, useEffect와 같은 훅(hook)을 사용하여 상태 및 생명 주기를 관리합니다.
- 빌드 크기: 클래스형 컴포넌트보다 빌드 크기가 작고 성능이 더 좋을 수 있습니다.
const MyComponent = () => {
const [count, setCount] = useState(0);
useEffect(() => {
// 컴포넌트가 마운트된 후 실행
}, []);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>{count}</p>
<button onClick={increment}>Increment</button>
</div>
);
};
3. 주요 차이점:
- 구조: 클래스형 컴포넌트는 클래스 기반이고, 함수형 컴포넌트는 함수 기반입니다.
- 생명 주기 관리: 클래스형 컴포넌트는 생명 주기 메서드를 사용하고, 함수형 컴포넌트는 훅(hook)을 사용합니다.
- 빌드 및 성능: 함수형 컴포넌트는 빌드 크기가 작고, 성능이 더 좋을 수 있습니다.
- 가독성 및 간결성: 함수형 컴포넌트는 코드가 더 간결하고 가독성이 좋습니다.
React의 장점과 단점을 설명해 주세요.
1. 장점:
컴포넌트 기반 구조:
React는 UI를 독립적이고 재사용 가능한 컴포넌트로 구성할 수 있게 합니다. 이를 통해 코드의 재사용성을 높이고, 유지보수를 쉽게 할 수 있습니다.
- 예시: 버튼, 입력 폼, 네비게이션 바 등을 각각의 컴포넌트로 만들어 필요할 때마다 재사용할 수 있습니다.
단방향 데이터 흐름:
React는 단방향 데이터 흐름을 채택하여 데이터의 흐름을 예측 가능하게 하고 디버깅을 쉽게 합니다. 부모 컴포넌트가 자식 컴포넌트에 데이터를 전달하는 방식으로 데이터가 흐릅니다.
- 예시: 상태(state)를 부모 컴포넌트에서 관리하고, 자식 컴포넌트에 props로 전달합니다.
Virtual DOM:
Virtual DOM을 사용하여 실제 DOM 조작을 최소화하고, 변경된 부분만 업데이트하여 성능을 최적화합니다.
- 예시: 상태가 변경되면 새로운 Virtual DOM 트리가 생성되고, 이전 트리와 비교하여 차이점만 실제 DOM에 반영됩니다.
풍부한 생태계:
React는 강력한 커뮤니티와 풍부한 생태계를 가지고 있어 다양한 라이브러리와 도구를 쉽게 통합할 수 있습니다.
- 예시: React Router를 사용한 라우팅, Redux를 사용한 상태 관리 등.
- 단점:
빠른 변화:
React의 생태계는 빠르게 변화하고 있어 최신 정보를 따라가는 것이 어려울 수 있습니다. 새로운 버전이 자주 릴리즈되며, 이에 따라 변경 사항을 학습해야 합니다.
- 예시: Hooks의 도입으로 기존 클래스형 컴포넌트에서 함수형 컴포넌트로의 전환 필요성.
초기 학습 곡선:
React의 개념과 JSX 문법에 익숙해지기까지 시간이 걸릴 수 있습니다. 특히 초보자에게는 컴포넌트 기반 구조와 상태 관리 등의 개념이 어려울 수 있습니다.
- 예시: JSX 문법을 처음 접하는 경우 HTML과 JavaScript가 혼합된 형태에 익숙해지기까지 시간이 필요합니다.
의존성 관리:
React 프로젝트는 다양한 라이브러리와 도구에 의존하는 경우가 많아, 의존성 관리를 신경 써야 합니다.
- 예시: 다양한 외부 라이브러리 사용으로 인해 패키지 업데이트와 호환성 문제 발생 가능성.
JSX란 무엇인가요?
JSX는 JavaScript XML의 약자로, React에서 사용하는 특별한 문법입니다. JSX를 사용하면 HTML 구조를 JavaScript 코드 안에서 작성할 수 있습니다.
- 기본 개념:
- JSX: JavaScript 내에서 HTML과 유사한 문법을 사용할 수 있게 해줍니다. 이는 React 컴포넌트를 정의하고, 렌더링하기 위해 주로 사용됩니다.
- 변환: 브라우저는 JSX를 직접 이해할 수 없기 때문에, Babel과 같은 트랜스파일러를 사용하여 JSX를 일반 JavaScript로 변환합니다.
2. 장점:
- 가독성 향상: JSX를 사용하면 UI 구조를 더 직관적이고 가독성 있게 작성할 수 있습니다. HTML과 유사한 문법으로 인해 개발자들이 쉽게 이해할 수 있습니다.
- 표현력: JSX는 JavaScript의 모든 기능을 사용할 수 있기 때문에, 조건부 렌더링, 반복문 등을 쉽게 표현할 수 있습니다.
3. 특징:
- JavaScript 표현식 포함: JSX 내에서 중괄호 {}를 사용하여 JavaScript 표현식을 포함할 수 있습니다.
- XML 기반 문법: HTML과 유사한 문법을 사용하므로, 기존 HTML 문법에 익숙한 개발자들이 쉽게 배울 수 있습니다.
- React 요소 생성: JSX는 React 요소를 생성하는 데 사용되며, Babel을 통해 React.createElement 호출로 변환됩니다.
// JSX 문법을 사용한 React 컴포넌트 예시
const MyComponent = () => {
const name = "React";
return (
<div>
<h1>Hello, {name}!</h1>
<p>This is a JSX example.</p>
</div>
);
};
// Babel을 통해 변환된 JavaScript 코드
const MyComponent = () => {
const name = "React";
return React.createElement(
"div",
null,
React.createElement("h1", null, `Hello, ${name}!`),
React.createElement("p", null, "This is a JSX example.")
);
};
브라우저는 JSX 파일을 읽을 수 있나요?
브라우저는 JSX 파일을 직접 읽을 수 없습니다. JSX는 JavaScript XML의 약자로, JavaScript 코드 내에서 HTML과 유사한 문법을 사용할 수 있게 해주는 특별한 문법입니다. 브라우저는 이 특별한 문법을 이해하지 못하기 때문에, JSX 코드를 브라우저가 이해할 수 있는 일반 JavaScript 코드로 변환해야 합니다. 이 과정은 Babel과 같은 트랜스파일러를 통해 이루어집니다.
- JSX의 변환:
- Babel: JSX 코드를 일반 JavaScript 코드로 변환하는 데 주로 사용되는 트랜스파일러입니다. Babel을 사용하면 브라우저가 이해할 수 있는 형태로 코드를 변환할 수 있습니다.
- 변환 과정: JSX 코드는 Babel을 통해 React.createElement 호출로 변환됩니다. 이를 통해 브라우저는 변환된 JavaScript 코드를 읽고 실행할 수 있습니다.
// JSX 코드
const MyComponent = () => {
return <h1>Hello, World!</h1>;
};
// Babel을 통해 변환된 JavaScript 코드
const MyComponent = () => {
return React.createElement('h1', null, 'Hello, World!');
};
3. 실제 사용:
- 개발 환경: 개발 시에는 Babel을 설정하여 JSX 파일을 변환하도록 해야 합니다. 주로 Webpack과 같은 모듈 번들러와 함께 사용됩니다.
- 생산 환경: 변환된 JavaScript 파일을 배포하여 브라우저가 이를 읽고 실행할 수 있게 합니다.
재조정(Reconciliation) 개념에 대해서 설명해 주세요.
재조정(Reconciliation)은 React에서 Virtual DOM을 사용하여 실제 DOM의 변경 사항을 효율적으로 업데이트하는 과정입니다. React는 상태(state)나 속성(props)이 변경될 때마다 새로운 Virtual DOM을 생성하고, 이전 Virtual DOM과 비교하여 변경된 부분만 실제 DOM에 반영합니다. 이 과정을 재조정이라고 합니다.
- 기본 개념:
- Virtual DOM: React는 UI를 표현하기 위해 메모리 내에 가벼운 Virtual DOM을 유지합니다.
- 변경 사항 비교: React는 새로운 Virtual DOM과 이전 Virtual DOM을 비교하여 변경된 부분을 찾아냅니다. 이 과정을 "diffing"이라고 합니다.
- 효율적 업데이트: 변경된 부분만 실제 DOM에 업데이트하여 성능을 최적화합니다.
2. 작동 방식:
- 새로운 Virtual DOM 생성: 상태(state)나 속성(props)이 변경되면, React는 새로운 Virtual DOM 트리를 생성합니다.
- Diffing: React는 이전 Virtual DOM과 새로운 Virtual DOM을 비교하여 변경된 요소를 찾아냅니다.
- 패치(Patching): 변경된 요소들만 실제 DOM에 업데이트합니다.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>{this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
state와 props의 차이를 설명해 주세요.
React에서 state와 props는 컴포넌트의 데이터를 관리하고 전달하는 데 중요한 역할을 합니다.
State:
- 정의: state는 컴포넌트 내부에서 관리되는 동적인 데이터입니다. 컴포넌트의 상태를 나타내며, 시간이 지남에 따라 변경될 수 있습니다.
- 관리: state는 컴포넌트 자체에서 관리하고, setState 메서드를 통해 업데이트합니다. state가 변경되면 컴포넌트는 다시 렌더링됩니다.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>{this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
특징:
- 컴포넌트 내부에서만 관리되고, 외부에서 직접 접근하거나 수정할 수 없습니다.
- 컴포넌트가 다시 렌더링될 때마다 초기화되지 않습니다.
Props:
- 정의: props는 부모 컴포넌트가 자식 컴포넌트에 전달하는 데이터입니다. 읽기 전용이며, 자식 컴포넌트는 props를 직접 수정할 수 없습니다.
- 전달: 부모 컴포넌트에서 자식 컴포넌트로 데이터나 함수를 전달할 때 사용됩니다.
// 부모 컴포넌트
class ParentComponent extends React.Component {
render() {
return <ChildComponent message="Hello, World!" />;
}
}
// 자식 컴포넌트
const ChildComponent = (props) => {
return <p>{props.message}</p>;
};
특징:
- 부모 컴포넌트가 자식 컴포넌트에 데이터를 전달하는 매개체 역할을 합니다.
- 자식 컴포넌트는 전달받은 props를 읽기만 할 수 있고, 수정할 수 없습니다.
- 컴포넌트가 다시 렌더링될 때마다 props는 새롭게 전달됩니다.
주요 차이점:
- 데이터 소유권: state는 컴포넌트 자체에서 소유하고 관리하는 데이터이고, props는 부모 컴포넌트가 소유하고 자식 컴포넌트에 전달하는 데이터입니다.
- 업데이트 방식: state는 setState 메서드를 통해 내부에서 업데이트할 수 있지만, props는 부모 컴포넌트에서 전달되므로 자식 컴포넌트에서 직접 업데이트할 수 없습니다.
- 목적: state는 컴포넌트의 동적인 상태를 관리하는 데 사용되고, props는 컴포넌트 간의 데이터 전달을 위해 사용됩니다.
자식 컴포넌트에서 props를 변경할 수 있나요?
아니요, 자식 컴포넌트는 props를 변경할 수 없습니다. props는 부모 컴포넌트에서 자식 컴포넌트로 전달되는 읽기 전용 데이터입니다. React의 설계 철학에 따라 데이터의 흐름은 단방향(Top-Down)으로 이루어지며, 이는 부모 컴포넌트가 자식 컴포넌트에 데이터를 전달하고, 자식 컴포넌트는 이를 읽기만 하는 구조입니다.
자식 컴포넌트가 props를 변경하려고 시도하면 React는 이를 무시하며, 오류를 발생시키지는 않지만 예상치 못한 동작을 초래할 수 있습니다. props를 변경해야 하는 경우, 자식 컴포넌트에서 부모 컴포넌트로 콜백 함수를 전달받아 이를 호출함으로써 부모 컴포넌트에서 상태를 업데이트하고, 새로운 값을 props로 전달하는 방식을 사용해야 합니다.
state를 직접 변경하지 않고 setState를 사용하는 이유를 설명해 주세요.
state를 직접 변경하지 않고 setState를 사용하는 이유는 React가 state 변경을 감지하고 컴포넌트를 다시 렌더링하기 위해서입니다. setState는 변경된 state를 큐에 넣고, React는 이를 최적화된 방식으로 처리하여 필요한 경우에만 다시 렌더링합니다.
- 변경 감지: React는 setState를 통해 전달된 변경 사항을 감지합니다. 직접 state를 변경하면 React가 이를 인지하지 못해 컴포넌트를 다시 렌더링하지 않습니다. 이는 state 변화에 따른 UI 업데이트가 이루어지지 않음을 의미합니다.
- 최적화된 렌더링: setState는 여러 state 변경을 하나의 업데이트로 배치(Batch) 처리합니다. 이를 통해 불필요한 렌더링을 방지하고 성능을 최적화합니다. 직접 state를 변경하면 이러한 최적화가 불가능해지고, 성능 저하가 발생할 수 있습니다.
- 일관성 유지: setState는 비동기적으로 작동하여 state 변경이 일관되게 처리되도록 보장합니다. 직접 state를 변경하면 동기적인 문제가 발생할 수 있으며, 이는 예기치 않은 버그로 이어질 수 있습니다.
Props drilling의 개념과 Props drilling을 피하는 방법에 대해 설명해 주세요.
Props drilling은 데이터를 상위 컴포넌트에서 하위 컴포넌트로 전달할 때, 중간에 위치한 여러 컴포넌트를 통해 전달해야 하는 상황을 의미합니다. 이는 코드의 복잡성을 증가시키고 유지보수를 어렵게 만듭니다. Props drilling은 특히 많은 계층을 거쳐 데이터를 전달해야 할 때 문제가 되며, 중간 컴포넌트들이 실제로 필요하지 않은 props를 받아야 하는 불편함이 발생합니다.
- Context API 사용: React의 Context API를 사용하여 전역적으로 데이터를 공유할 수 있습니다. Context API를 통해 중간 컴포넌트를 거치지 않고 필요한 컴포넌트에서 직접 데이터를 접근할 수 있습니다. 이는 주로 테마, 인증 정보, 사용자 설정 등 전역적인 데이터에 유용합니다. Context를 사용하면 필요할 때 원하는 컴포넌트에서 손쉽게 데이터를 소비할 수 있습니다.
2. 상태 관리 라이브러리 사용: Redux, MobX 등의 상태 관리 라이브러리를 사용하여 전역 상태를 관리할 수 있습니다. 이러한 라이브러리는 애플리케이션의 상태를 중앙 집중식으로 관리하므로, props drilling 없이 필요한 컴포넌트에서 상태를 접근하고 업데이트할 수 있습니다. Redux와 MobX는 상태를 일관성 있게 관리하고, 복잡한 상태 변경 로직을 쉽게 처리할 수 있게 도와줍니다.
React Hooks에 대해 설명해 주세요.
React Hooks는 함수형 컴포넌트에서 상태와 생명주기 기능을 사용할 수 있게 해주는 기능입니다. React v16.8에서 도입되었으며, 이를 통해 클래스형 컴포넌트 없이도 상태 관리와 생명주기 메서드를 활용할 수 있습니다. Hooks는 함수형 컴포넌트를 더욱 강력하고 유연하게 만들어 주며, 재사용 가능한 상태 로직을 쉽게 작성할 수 있게 해줍니다.
- useState: 컴포넌트에서 상태를 관리할 수 있게 해주는 Hook입니다. 초기 상태 값을 인자로 받아 현재 상태와 상태를 업데이트하는 함수를 반환합니다.
- useEffect: 부수 효과를 수행하기 위한 Hook입니다. 데이터 가져오기, 구독 설정, DOM 조작 등을 할 때 사용되며, 의존성 배열을 통해 특정 조건에서만 실행되도록 설정할 수 있습니다.
- useContext: 컨텍스트를 쉽게 사용할 수 있게 해주는 Hook입니다. 컨텍스트의 값을 읽고, 해당 컨텍스트가 제공하는 값이 변경될 때 컴포넌트를 다시 렌더링합니다.
- useReducer: 복잡한 상태 로직을 관리할 때 유용한 Hook입니다. 리듀서 패턴을 사용하여 상태와 업데이트 로직을 분리하고 관리할 수 있습니다.
React Lifecycle에 대해 설명해 주세요.
React Lifecycle은 컴포넌트의 생성, 업데이트, 소멸 과정을 의미합니다. 이 과정은 클래스형 컴포넌트에서 주로 생명주기 메서드를 통해 관리되며, 함수형 컴포넌트에서는 Hook을 사용하여 동일한 작업을 수행합니다.
- 생성 (Mounting): 컴포넌트가 처음 DOM에 삽입될 때 발생하는 과정입니다. 주요 메서드로는 componentDidMount가 있습니다. 이 메서드는 컴포넌트가 처음 렌더링된 후에 호출되며, 주로 데이터 가져오기나 초기화 작업에 사용됩니다.
- 업데이트 (Updating): 컴포넌트가 상태나 props의 변화로 인해 다시 렌더링될 때 발생하는 과정입니다. 주요 메서드로는 componentDidUpdate가 있습니다. 이 메서드는 컴포넌트가 업데이트된 후에 호출되며, DOM을 조작하거나 상태에 따른 부수 효과를 처리하는 데 사용됩니다.
- 소멸 (Unmounting): 컴포넌트가 DOM에서 제거될 때 발생하는 과정입니다. 주요 메서드로는 componentWillUnmount가 있습니다. 이 메서드는 컴포넌트가 DOM에서 제거되기 직전에 호출되며, 구독 해제나 타이머 정리와 같은 정리 작업을 수행하는 데 사용됩니다.
React 라이프사이클 메서드
- constructor: 컴포넌트가 처음 생성될 때 호출됩니다. 초기 state를 설정하거나 인스턴스에 메서드를 바인딩할 때 주로 사용됩니다.
- componentDidMount: 컴포넌트가 처음 렌더링된 후 호출됩니다. API 호출이나 DOM 조작과 같은 작업을 수행하기에 적합합니다.
- shouldComponentUpdate: 컴포넌트가 다시 렌더링될지 여부를 결정합니다. 성능 최적화를 위해 사용됩니다.
- componentDidUpdate: 컴포넌트가 업데이트된 후 호출됩니다. 업데이트 후 작업이 필요할 때 사용됩니다.
- componentWillUnmount: 컴포넌트가 DOM에서 제거되기 직전에 호출됩니다. 타이머를 정리하거나 구독을 취소할 때 유용합니다.
import React, { Component } from 'react';
class LifecycleDemo extends Component {
// constructor 메서드
constructor(props) {
super(props);
this.state = { count: 0 };
console.log('constructor: 컴포넌트가 생성되었습니다.');
}
// componentDidMount 메서드
componentDidMount() {
console.log('componentDidMount: 컴포넌트가 마운트되었습니다.');
}
// shouldComponentUpdate 메서드
shouldComponentUpdate(nextProps, nextState) {
console.log('shouldComponentUpdate: 컴포넌트가 업데이트될까요?', nextState);
return true; // false를 반환하면 업데이트를 막을 수 있습니다.
}
// componentDidUpdate 메서드
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate: 컴포넌트가 업데이트되었습니다.', prevState);
}
// componentWillUnmount 메서드
componentWillUnmount() {
console.log('componentWillUnmount: 컴포넌트가 언마운트됩니다.');
}
// 버튼 클릭 핸들러
handleClick = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
console.log('render: 컴포넌트가 렌더링됩니다.');
return (
<div>
<h1>React 라이프사이클 데모</h1>
<p>카운트: {this.state.count}</p>
<button onClick={this.handleClick}>증가</button>
</div>
);
}
}
export default LifecycleDemo;
useEffect와 useLayoutEffect의 차이에 대해 설명해 주세요.
useEffect와 useLayoutEffect는 모두 React의 Hook으로, 함수형 컴포넌트에서 부수 효과를 수행하는 데 사용됩니다.
- useEffect: useEffect는 컴포넌트가 렌더링된 후에 실행됩니다. 즉, 브라우저가 DOM을 업데이트하고 화면에 그린 후에 실행되기 때문에, 비동기 작업이나 데이터 가져오기 등에 주로 사용됩니다. useEffect는 성능 최적화를 위해 브라우저가 화면을 업데이트한 후에 부수 효과를 처리하도록 설계되었습니다. 이로 인해 UI가 렌더링된 후에 상태 업데이트나 네트워크 요청 등을 수행할 수 있습니다.
import React, { useEffect, useState } from 'react';
const MyComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => setData(data));
}, []);
return (
<div>
<p>Data: {data}</p>
</div>
);
};
- useLayoutEffect: useLayoutEffect는 DOM이 변경된 직후, 화면에 그려지기 전에 실행됩니다. 이 Hook은 동기적으로 실행되며, 레이아웃을 조정하거나 DOM을 즉시 조작해야 하는 작업에 적합합니다. 예를 들어, 요소의 크기나 위치를 계산하고 이를 기반으로 다른 DOM 조작을 해야 할 때 useLayoutEffect를 사용합니다. useLayoutEffect는 DOM이 완전히 그려지기 전에 실행되므로, 시각적 오류 없이 DOM을 동기적으로 조작할 수 있습니다.
import React, { useLayoutEffect, useRef } from 'react';
const MyComponent = () => {
const divRef = useRef();
useLayoutEffect(() => {
const div = divRef.current;
console.log(div.getBoundingClientRect());
}, []);
return (
<div ref={divRef}>
<p>Layout Effect Example</p>
</div>
);
};
useState에 대해 설명해 주세요.
useState는 React의 함수형 컴포넌트에서 상태를 관리하기 위한 Hook입니다. 이 Hook은 초기 상태 값을 인자로 받아, 현재 상태 값과 이 상태를 업데이트할 수 있는 함수를 반환합니다. 이 함수는 상태를 업데이트할 때마다 컴포넌트를 다시 렌더링하게 만듭니다.
useState는 배열을 반환하며, 배열의 첫 번째 요소는 현재 상태 값을 나타내고, 두 번째 요소는 상태를 업데이트하는 함수입니다.
상태 업데이트 함수에 새로운 상태 값을 전달하면 컴포넌트가 다시 렌더링되며, 최신 상태 값이 반영됩니다. useState는 함수형 컴포넌트에서도 클래스형 컴포넌트처럼 상태를 관리할 수 있게 해 주며, 더 간단하고 직관적인 상태 관리 방법을 제공합니다.
import React, { useState } from 'react';
function Counter() {
// useState를 사용하여 count 상태와 setCount 상태 업데이트 함수를 정의
const [count, setCount] = useState(0);
// 버튼 클릭 시 호출되는 함수
const increment = () => {
setCount(count + 1); // count 상태를 1 증가
};
return (
<div>
<h1>Counter: {count}</h1>
<button onClick={increment}>Increment</button>
</div>
);
}
export default Counter;
useEffect에 대해 설명해 주세요.
useEffect는 React의 함수형 컴포넌트에서 부수 효과를 수행하기 위한 Hook입니다. 이 Hook은 컴포넌트가 렌더링된 후에 실행되며, 주로 데이터 가져오기, 구독 설정, DOM 조작 등의 작업을 수행합니다. useEffect는 첫 번째 인자로 실행할 함수를 받고, 두 번째 인자로는 의존성 배열을 받습니다.
의존성 배열을 빈 배열로 전달하면, 이 함수는 컴포넌트가 처음 마운트될 때 한 번만 실행됩니다. 반면, 특정 상태나 props를 의존성 배열에 전달하면, 해당 값들이 변경될 때마다 useEffect 내의 함수가 실행됩니다. 이를 통해 컴포넌트가 특정 상태 변화에 따라 동작하도록 만들 수 있습니다.
import React, { useState, useEffect } from 'react';
function ExampleComponent() {
const [count, setCount] = useState(0);
const [data, setData] = useState(null);
// 컴포넌트가 마운트될 때와 count 상태가 업데이트될 때 실행
useEffect(() => {
console.log('컴포넌트가 마운트되거나 count가 업데이트되었습니다.');
// API 호출 예시 (마운트 시점에서 한 번만 실행됨)
if (count === 0) {
fetch('https://api.example.com/data')
.then((response) => response.json())
.then((data) => setData(data));
}
// 클린업 함수 (언마운트 시점에서 실행)
return () => {
console.log('컴포넌트가 언마운트되었습니다.');
};
}, [count]); // count가 변경될 때마다 실행
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
{data && <div>Data: {JSON.stringify(data)}</div>}
</div>
);
}
export default ExampleComponent;
useEffect에 대해 생명 주기와 비교하면서 설명해 주세요.
useEffect 훅은 React 함수형 컴포넌트에서 사이드 이펙트를 처리하기 위해 사용됩니다. 클래스형 컴포넌트의 생명 주기 메서드와 비교하면, useEffect는 마운트, 업데이트, 언마운트 시점에 따라 다양한 방식으로 작동합니다.
마운트(Mount):
- 생명 주기 메서드: 클래스형 컴포넌트에서는 componentDidMount 메서드가 컴포넌트가 처음 마운트된 후에 호출됩니다.
- useEffect: 의존성 배열이 빈 배열([])인 경우, useEffect는 컴포넌트가 처음 마운트된 후에 한 번 실행됩니다.
useEffect(() => {
// 컴포넌트가 마운트된 후에 실행
console.log('Component mounted');
}, []);
업데이트(Update):
- 생명 주기 메서드: 클래스형 컴포넌트에서는 componentDidUpdate 메서드가 상태(state)나 props가 변경될 때마다 호출됩니다.
- useEffect: 의존성 배열에 특정 값이 있는 경우, 해당 값이 변경될 때마다 useEffect가 실행됩니다.
useEffect(() => {
// count 값이 변경될 때마다 실행
console.log('Count updated:', count);
}, [count]);
언마운트(Unmount):
- 생명 주기 메서드: 클래스형 컴포넌트에서는 componentWillUnmount 메서드가 컴포넌트가 언마운트되기 직전에 호출됩니다.
- useEffect: useEffect 훅에서 반환하는 함수가 컴포넌트가 언마운트되기 직전에 실행됩니다. 이를 cleanup 함수라고 합니다.
useEffect(() => {
// 컴포넌트가 마운트된 후에 실행
console.log('Effect');
// cleanup 함수
return () => {
console.log('Component unmounted');
};
}, []);
의존성 배열이 없는 경우:
- 생명 주기 메서드: 클래스형 컴포넌트에서는 매 렌더링 후에 componentDidUpdate가 호출됩니다.
- useEffect: 의존성 배열이 없는 경우, useEffect는 매 렌더링 후에 실행됩니다.
useEffect(() => {
// 매 렌더링 후에 실행
console.log('Component rendered');
});
React 렌더링 성능을 향상하기 위한 방법들을 설명해 주세요.
- 컴포넌트 메모이제이션: React.memo를 사용하여 컴포넌트를 메모이제이션하면, props가 변경되지 않는 한 컴포넌트를 재렌더링하지 않습니다.
- useMemo와 useCallback: useMemo를 사용하여 값의 계산을 메모이제이션하고, useCallback을 사용하여 함수를 메모이제이션함으로써 불필요한 재연산과 재렌더링을 방지할 수 있습니다.
- shouldComponentUpdate와 React.PureComponent: 클래스형 컴포넌트에서 shouldComponentUpdate 메서드를 구현하거나 React.PureComponent를 사용하여 컴포넌트의 불필요한 업데이트를 방지할 수 있습니다.
- 코드 스플리팅: React.lazy와 Suspense를 사용하여 코드 스플리팅을 하면, 초기 로딩 속도를 향상시킬 수 있습니다.
- 리스트 렌더링 최적화: 리스트를 렌더링할 때 key 속성을 적절하게 설정하고, react-window나 react-virtualized와 같은 라이브러리를 사용하여 가상 스크롤링을 구현하면 성능을 개선할 수 있습니다.
- 브라우저 최적화: requestAnimationFrame을 사용하여 애니메이션을 최적화하고, CSS 애니메이션을 활용하여 리플로우와 리페인트를 최소화합니다.
- 불필요한 렌더링 방지: 상태를 최소한의 컴포넌트에 유지하고, 상태 변경이 필요하지 않은 컴포넌트에는 상태를 전파하지 않도록 합니다.
Context API에 대해 설명해 주세요.
Context API는 컴포넌트 트리 전체에 걸쳐 데이터를 전송할 수 있게 해주는 방법입니다. 이를 통해 중간에 위치한 컴포넌트들을 거치지 않고도 props를 전달할 수 있습니다. Context API는 전역 상태 관리가 필요할 때 특히 유용합니다. 주요 구성 요소로는 createContext, Provider, Consumer가 있으며, 함수형 컴포넌트에서는 useContext Hook을 사용하여 간편하게 Context 값을 구독할 수 있습니다.
Context API의 주요 구성 요소
- React.createContext: Context 객체를 생성합니다.
- Provider: Context를 구독하는 컴포넌트들에게 context 값을 전송합니다.
- Consumer: Context의 현재 값을 구독합니다. 함수형 컴포넌트에서는 useContext Hook을 주로 사용합니다.
import React, { createContext, useState } from 'react';
// Context 생성
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
export default ThemeContext;
import React from 'react';
import { ThemeProvider } from './ThemeContext';
import ThemedComponent from './ThemedComponent';
function App() {
return (
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
}
export default App;
import React, { useContext } from 'react';
import ThemeContext from './ThemeContext';
const ThemedComponent = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
const style = {
backgroundColor: theme === 'light' ? '#fff' : '#333',
color: theme === 'light' ? '#000' : '#fff',
padding: '20px',
textAlign: 'center',
};
return (
<div style={style}>
<p>현재 테마: {theme}</p>
<button onClick={toggleTheme}>테마 전환</button>
</div>
);
};
export default ThemedComponent;
redux와 context api에 대해서 설명을 해주세요. 또한 주로 사용하는 상황에 대해서도 서술 하세요.
Redux는 애플리케이션의 상태를 중앙에서 관리하는 라이브러리입니다. 중앙 집중식 상태 관리, 액션과 리듀서, 미들웨어 지원, 타임 트래블 디버깅 기능을 제공하여 상태 변경을 예측 가능하고 추적 가능하게 합니다. 주로 대규모 애플리케이션에서 상태 관리가 복잡할 때 사용됩니다.
Context API는 React 내장 기능으로, props를 통해 데이터를 전달하지 않고도 컴포넌트 트리 전체에 걸쳐 데이터를 전파할 수 있습니다. Provider와 Consumer를 사용하여 간단한 전역 상태 관리를 제공하며, 주로 테마, 사용자 인증 상태, 현재 언어와 같은 간단한 전역 데이터 관리에 사용됩니다.
Redux
Redux는 애플리케이션의 상태를 중앙에서 관리하는 라이브러리입니다. 다음은 Redux의 주요 특징과 사용 사례입니다:
- 중앙 집중식 상태 관리: Redux는 애플리케이션의 전체 상태를 하나의 스토어에서 관리합니다. 이는 상태를 예측 가능하게 하고, 상태 변경의 추적을 용이하게 합니다.
- 액션과 리듀서: 상태를 변경하려면 액션을 디스패치해야 하며, 리듀서가 이 액션을 처리하여 새로운 상태를 반환합니다.
- 미들웨어: Redux는 미들웨어를 통해 비동기 작업을 처리할 수 있습니다. 대표적인 미들웨어로는 Redux Thunk와 Redux Saga가 있습니다.
- 타임 트래블 디버깅: Redux DevTools를 사용하면 상태 변경을 추적하고, 이전 상태로 되돌리거나 상태 변경을 재생할 수 있습니다.
주로 사용하는 상황:
- 상태 관리가 복잡한 대규모 애플리케이션
- 다수의 컴포넌트에서 상태를 공유해야 하는 경우
- 상태 변경 로직을 명확하게 관리하고 추적해야 하는 경우
Context API
Context API는 React 내장 기능으로, props를 일일이 전달하지 않고도 컴포넌트 트리 전반에 걸쳐 데이터를 전파할 수 있게 해줍니다. 다음은 Context API의 주요 특징과 사용 사례입니다:
- 프로바이더와 컨슈머: Context를 생성하면 Provider와 Consumer를 사용할 수 있습니다. Provider는 데이터를 전파하고, Consumer는 데이터를 구독합니다.
- 경량 상태 관리: Context API는 전역 상태 관리가 필요한 간단한 상황에서 유용합니다.
- Hook과의 통합: useContext Hook을 사용하여 함수형 컴포넌트에서 간편하게 Context를 사용할 수 있습니다.
주로 사용하는 상황:
- 단순한 전역 상태 관리
- 테마, 사용자 인증 상태, 현재 언어와 같은 간단한 전역 데이터
- props 드릴링을 피하고 싶은 경우
import { createStore } from 'redux';
const initialState = {
count: 0,
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
default:
return state;
}
};
const store = createStore(reducer);
export default store;
import React from 'react';
import { Provider, useDispatch, useSelector } from 'react-redux';
import store from './store';
const Counter = () => {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<h1>{count}</h1>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button>
</div>
);
};
const App = () => (
<Provider store={store}>
<Counter />
</Provider>
);
export default App;
import React, { createContext, useState } from 'react';
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
export default ThemeContext;
import React, { useContext } from 'react';
import { ThemeProvider, ThemeContext } from './ThemeContext';
const ThemedComponent = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
<p>현재 테마: {theme}</p>
<button onClick={toggleTheme}>테마 전환</button>
</div>
);
};
const App = () => (
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
export default App;
Redux는 Flux 패턴을 보고 영감을 받아 만들어진 상태 관리 라이브러리인데요, Redux와 Flux 패턴에 대해 비교를 해주세요.
Redux는 단일 Store와 Reducer를 사용하여 상태를 관리하며, Dispatcher를 사용하지 않습니다. Flux는 여러 Store와 중앙 Dispatcher를 사용하여 상태를 관리합니다. Redux는 상태 관리가 복잡한 대규모 애플리케이션에서 주로 사용되며, Flux는 비교적 단순한 상태 관리가 필요한 경우에 사용됩니다.
Flux 패턴
Flux는 Facebook에서 만든 애플리케이션 아키텍처로, 단방향 데이터 흐름을 강조합니다. Flux의 주요 구성 요소는 다음과 같습니다:
- Action: 상태 변경을 일으키는 객체입니다. 액션은 type 속성과 필요한 추가 데이터를 포함합니다.
- Dispatcher: 모든 액션이 통과하는 중앙 허브입니다. Dispatcher는 액션을 받아서 등록된 콜백(스토어)에 전달합니다.
- Store: 애플리케이션의 상태와 상태 변경 로직을 포함합니다. 여러 개의 스토어가 있을 수 있습니다.
- View: React 컴포넌트와 같이 사용자 인터페이스를 렌더링하는 부분입니다. View는 Store로부터 상태를 받아와서 렌더링합니다.
Flux의 데이터 흐름:
Action -> Dispatcher -> Store -> View
Redux
Redux는 Flux에서 영감을 받아 만들어진 상태 관리 라이브러리로, 더 단순화된 구조를 가지고 있습니다. Redux의 주요 구성 요소는 다음과 같습니다:
- Action: 상태 변경을 일으키는 객체입니다. Flux와 유사하게 type 속성과 추가 데이터를 포함합니다.
- Reducer: 상태를 변경하는 순수 함수입니다. 액션을 받아 현재 상태를 기반으로 새로운 상태를 반환합니다.
- Store: 애플리케이션의 상태와 상태 변경 로직을 포함합니다. 단 하나의 스토어만 존재합니다.
- View: React 컴포넌트와 같이 사용자 인터페이스를 렌더링하는 부분입니다. View는 Store로부터 상태를 받아와서 렌더링합니다.
Redux의 데이터 흐름:
Action -> Reducer -> Store -> View
useContext Hook에 대해 설명해 주세요.
useContext Hook은 함수형 컴포넌트에서 Context를 사용하기 위해 제공되는 Hook입니다. 이를 통해 props를 일일이 전달하지 않고도 컴포넌트 트리 전체에 걸쳐 데이터를 쉽게 공유할 수 있습니다. useContext는 Context 객체를 인자로 받아 현재 Context 값을 반환하며, Context를 구독하는 컴포넌트는 제공된 Context 값이 변경될 때마다 다시 렌더링됩니다.
useContext 사용 방법
- Context 생성: createContext 함수를 사용하여 Context를 생성합니다.
- Provider: Provider 컴포넌트를 사용하여 하위 컴포넌트에 Context 값을 제공합니다.
- useContext: 함수형 컴포넌트에서 useContext Hook을 사용하여 Context 값을 읽습니다.
import React, { createContext, useState } from 'react';
// Context 생성
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
export default ThemeContext;
import React, { useContext } from 'react';
import ThemeContext from './ThemeContext';
const ThemedComponent = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
<p>현재 테마: {theme}</p>
<button onClick={toggleTheme}>테마 전환</button>
</div>
);
};
export default ThemedComponent;
React Router에 대해 설명해 주세요.
React Router는 React 애플리케이션에서 라우팅을 관리하기 위한 라이브러리입니다. 이를 통해 URL에 따라 다른 컴포넌트를 렌더링할 수 있습니다. 주요 구성 요소로는 <BrowserRouter>, <Route>, <Switch>, <Link>, <NavLink> 등이 있습니다. <BrowserRouter>는 HTML5의 History API를 사용하여 URL을 관리하고, <Route>는 특정 URL 경로에 따라 렌더링할 컴포넌트를 정의하며, <Switch>는 여러 <Route> 중 하나만 매칭되도록 합니다. <Link>와 <NavLink>는 사용자 인터페이스 내에서 경로를 변경할 수 있는 링크를 생성합니다.
import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
const Home = () => <h2>Home</h2>;
const About = () => <h2>About</h2>;
const Users = () => <h2>Users</h2>;
const App = () => (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
</nav>
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
export default App;
useState와 useReducer의 차이를 설명해 주세요.
useState와 useReducer는 React에서 상태 관리를 위해 제공되는 Hook입니다. useState는 간단한 상태 관리에 적합하며, 상태 값과 상태를 갱신하는 함수를 반환합니다. 반면에 useReducer는 복잡한 상태 관리 로직을 다룰 때 유용하며, 상태와 상태 변경 로직을 분리할 수 있습니다. useReducer는 현재 상태와 액션을 받아 새로운 상태를 반환하는 리듀서 함수를 사용하며, Redux와 유사한 패턴을 따릅니다. 복잡한 상태 전이 로직이나 여러 상태 업데이트가 관련된 경우에는 useReducer가 더 적합합니다.
- useState:
- 정의: useState는 컴포넌트 내에서 단순한 상태를 관리할 때 사용되는 훅입니다.
- 용도: 간단한 상태 관리에 적합하며, 상태는 기본적으로 단순한 값이나 객체일 수 있습니다.
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
특징:
- 간단한 상태 업데이트에 적합합니다.
- 상태 업데이트 함수(setCount)는 기존 상태에 새로운 값을 설정합니다.
- useReducer:
- 정의: useReducer는 더 복잡한 상태 로직을 처리하거나 여러 하위 값을 포함하는 상태를 관리할 때 사용되는 훅입니다.
- 용도: 복잡한 상태 로직이나 상태 전이 로직이 필요한 경우에 적합합니다.
import React, { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>{state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
};
- 특징:
- 복잡한 상태 로직을 처리하는 데 적합합니다.
- 상태 전이 로직을 reducer 함수로 정의하고, dispatch 함수를 사용하여 액션을 보냅니다.
- 주요 차이점:
- 상태 관리의 복잡성:
- useState: 간단한 상태 관리에 적합합니다.
- useReducer: 복잡한 상태 전이 로직이 필요하거나 상태 구조가 복잡한 경우에 적합합니다.
- 상태 업데이트 방법:
- useState: 직접 상태를 설정하는 함수(setState)를 사용합니다.
- useReducer: 액션을 디스패치하고, 리듀서 함수가 상태 전이를 처리합니다.
- 코드 구조:
- useState: 상태와 업데이트 함수를 간단하게 사용할 수 있습니다.
- useReducer: 리듀서 함수와 디스패치 액션을 사용하여 더 구조화된 상태 관리를 할 수 있습니다.