목차
1. 리액트 컴포넌트의 기본 구조
2. 컴포넌트의 상태 관리
3. 컴포넌트의 동작과 생명 주기
4. 컴포넌트 간의 상태 전달 방법
5. 컴포넌트의 DOM 참조
6. 컴포넌트의 동작과 사용자 인터렉션
[1] 리액트 컴포넌트의 기본 구조
(1) 부모-자식 컴포넌트
- 부모 컴포넌트는 다른 컴포넌트를 포함하고, 자식 컴포넌트에 데이터를 전달하는 역할
- 부모는 자식 컴포넌트를 렌더링하고, 그들에게 필요한 props를 전달하여 UI를 동적으로 구성함
// 부모 컴포넌트
function Parent() {
const [message, setMessage] = useState("Hello, React!");
const handleMessageChange = () => {
setMessage("Updated message from Parent");
};
return (
<div>
<h1>Parent Component</h1>
<Child message={message} onMessageChange={handleMessageChange} /> // Parent는 Child에게 message를 props로 전달하고, onMessageChange라는 콜백 함수도 전달
</div>
);
}
// 자식 컴포넌트
function Child({ message, onMessageChange }) {
return (
<div>
<h2>{message}</h2>
<button onClick={onMessageChange}>Change Message</button> // Child는 message를 화면에 출력하고, 버튼을 클릭하면 onMessageChange 함수를 호출하여 부모 컴포넌트의 상태를 업데이트
</div>
);
}
(2) Props(=Properties)
- 부모 컴포넌트에서 자식 컴포넌트로 전달되는 읽기 전용 데이터로, 모든 자바스크립트 값을 props로 전달할 수 있음
- props는 읽기 전용이므로, 자식 컴포넌트는 부모 컴포넌트에게서 전달 받은 props를 수정할 수 없음
- 주로 컴포넌트 간에 데이터를 전달하려는 목적으로 사용됨
- 컴포넌트는 props가 변경될 때마다 다시 렌더링(=리렌더링)됨
// 부모 컴포넌트
function Parent() {
const message = "Hello, World!";
return (
<div>
<Child message={message} /> // Parent는 message라는 데이터를 Child 컴포넌트에 props로 전달
</div>
);
}
// 자식 컴포넌트
function Child(props) {
return <h2>{props.message}</h2>; // Child는 props.message를 사용하여 데이터를 렌더링
}
[2] 컴포넌트의 상태 관리
State(=상태 = 상태 변수)
- 컴포넌트 내부에서 읽고 업데이트할 수 있는 값으로, 컴포넌트의 상태를 나타냄
- 일반 변수와 달리, 상태 변수는 변경되면 해당 상태를 참조하고 있는 컴포넌트는 자동으로 리렌더링됨
- 클래스형 컴포넌트는 setState() 메서드를 이용해 상태 변수를 변경함
// 클래스형 컴포넌트에서 setState() 메서드 사용 방법
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 }; // 초기 state 설정
}
increment = () => {
this.setState({ count: this.state.count + 1 }); // 상태 변경(=업데이트)
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increase</button>
</div>
);
}
}
// 배열이나 객체를 상태로 사용할 때 = 전개 연산자(...)를 사용하여 원본을 복사한 후 새로운 값을 추가
function TodoList() {
const [todos, setTodos] = useState([]);
const addTodo = (newTodo) => {
setTodos([...todos, newTodo]); // 기존 배열을 복사하여 새로운 아이템 추가
};
return (
<div>
<ul>
{todos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
</ul>
<button onClick={() => addTodo('New Task')}>Add Todo</button>
</div>
);
}
- 함수형 컴포넌트는 useState 훅 함수가 반환하는 setter함수(=업데이트 함수)를 이용해 상태 변수를 변경함
상태변수 세터함수 또는 업데이터 상태변수의 초기값
~~~~~~~ ~~~~~~~~~~ ~~
const [ message, setMessage ] = useState( '' );
^ ^ ~~~~~~~~~~~~~~
| | 상태 변수의 초기값과 상태 변수의 값을 변경할 때 사용할 함수를 배열로 반환
| | return [ 상태 변수의 초기값, 상태 변수의 값을 변경할 때 사용할 함수 ]
| | | |
+--------|----------------------------+ |
+-----------------------------------------------------+ ⇐ 배열 비구조화
[3] 컴포넌트의 동작과 생명 주기
(1) hooks
- 클래스형 컴포넌트에서 제공하던 기능(state, props, ref, life cycle method 등)을 함수형 컴포넌트에서 지원하기 위해 도입된 함수
- 함수 이름은 use 접두어를 사용함(useState, useEffect, useRef, ...)
1. useState - 상태 관리
- 함수형 컴포넌트에서 상태를 선언하고 관리할 수 있게 해주는 훅
- 이 훅은 [상태변수의 초기값, 상태변수의 값을 변경하는 함수] 배열을 반환
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0); // 상태 초기값은 0
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
// useState(initialValue) : 상태의 초기값을 설정
// setCount(value) : 상태를 변경하는 함수로, 이 함수가 호출될 때마다 해당 컴포넌트가 리렌더링
2. useEffect - 효과 관리
- Side Effects를 관리하는 훅
- 컴포넌트가 렌더링된 후에 비동기 작업이나 외부 데이터 가져오기, 구독 처리, 타이머 설정 등을 처리할 때 사용
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const timer = setInterval(() => setSeconds(prev => prev + 1), 1000);
// 컴포넌트가 unmount 될 때 타이머를 클리어
return () => clearInterval(timer);
}, []); // 빈 배열을 넣으면 마운트될 때 한 번만 실행
return <p>Time: {seconds}s</p>;
}
// useEffect(callback, dependencies) 로 구성
// callback은 부수효과를 처리하는 함수
// dependencies는 useEffect가 언제 실행될지 결정하는 의존성 배열로, 빈 배열[]은 마운트시 한 번만 실행
- 후처리 (cleanup) 함수 : useEffect 내부에서 반환된 함수로, 컴포넌트가 언마운트되거나, 의존성 배열에 지정된 값이 변경될 때 호출되어 사이드 이펙트를 처리하는데 사용
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// 초기화 작업: 이벤트 리스너 추가
const timer = setInterval(() => {
console.log('타이머 작동 중');
}, 1000);
// 후처리 함수: 컴포넌트가 언마운트되거나 의존성 배열이 변경될 때 호출
return () => {
clearInterval(timer); // 타이머 정리
console.log('타이머가 종료되었습니다.');
};
}, []); // 빈 배열은 컴포넌트가 마운트될 때 한 번만 실행
return <div>타이머가 작동 중입니다.</div>;
}
3. useRef - 참조 관리
- DOM(Document Object Model : HTML 요소들에 대한 객체 모델)요소나 값을 기억하는데 사용되는 훅
- 렌더링 없이 값을 지속적으로 저장하거나, DOM을 직접 조작할 때 사용
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef(); // ref 객체를 반환하며, 해당 객체는 렌더링 간에 유지되는 값을 저장함
const focusInput = () => {
inputRef.current.focus(); // ref를 통해 DOM 요소에 직접 접근
};
return (
<div>
<input ref={inputRef} />
<button onClick={focusInput}>Focus the input</button>
</div>
);
}
4. useMemo - 성능 최적화
- 계산 비용이 큰 값을 메모이제이션(memoization)하여 성능을 최적화하는데 사용하는 훅
// const memoizedValue = useMemo( () => computeExpensiveValue(a, b), [a, b] );
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~
// 계산을 수행하는 함수 의존성 배열 → 배열의 값이 변경되었을 때만 함수를 실행
// 의존성 배열을 넣지 않는 경우,
// 렌더링이 일어날 때마다 매번 함수를 실행
import React, { useMemo, useState } from 'react';
function ExpensiveCalculation() {
const [count, setCount] = useState(0);
const expensiveResult = useMemo(() => {
console.log('Calculating...');
return count * 2;
}, [count]); // count가 변경될 때만 계산
return (
<div>
<p>Result: {expensiveResult}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
5. useCallback - 함수 최적화
- 함수를 메모이제이션하여 불필요한 함수 재생성을 방지하는 훅
- 컴포넌트가 리렌더링될 때 동일한 콜백 함수가 사용되도록 하며, 자식 컴포넌트에 콜백 함수를 전달할 때 유용함
// const memorizedCallback = useCallback(() => { ... }, [ ... ]);
// ~~~~~~~~~~~~~ ~~~~~~
// 콜백 함수 의존성 배열 ⇒ 배열의 값이 변경될 때만 콜백 함수를 새로 생성
import React, { useCallback, useState } from 'react';
function Parent() {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount(count + 1), [count]);
return (
<div>
<Child onClick={increment} />
<p>Count: {count}</p>
</div>
);
}
function Child({ onClick }) {
return <button onClick={onClick}>Increment</button>;
}
6. useReducer - 상태 관리
- 상태와 상태를 업데이트하는 로직을 분리할 때 사용하는 훅
- 단순 상태 관리는 useState로도 가능하지만, 상태가 다단계로 변하거나 관련된 여러 상태를 관리해야할 때 적합
const [state, dispatch] = useReducer(reducer, initialState);
// reducer : 현재 상태와 액션을 기반으로 새 상태를 반환하는 함수
// initialState : 초기 상태
// dispatch : 액션을 발생시키는 함수
7. useContext - 데이터 전달
- 컴포넌트 트리 전체에 데이터를 전달해야 할 때 사용하는 훅
- 리액트에서는 일반적으로 props를 통해 데이터를 전달하지만, 여러 컴포넌트 계층을 거쳐야 하면 코드가 복잡해질 수 있기 때문에 전역으로 데이터를 공유하고자 하는 경우에 적합
사용법
1. React.createContext()로 컨텍스트를 생성
2. Context.Provider로 데이터를 공급
3. 하위 컴포넌트에서 useContext로 데이터를 사용
(2) life cycle(생명 주기)
- 컴포넌트가 생성, 업데이트, 소멸되는 과정에서 호출되는 메서드
- 함수형 컴포넌트에서는 useEffect 훅을 사용함
- 클래스형 컴포넌트에서는 생명 주기 메서드(DidMount, DidUpdate, WillUnmount)를 사용함
※주요 생명 주기 단계
(1) 마운트(Mount) : 컴포넌트가 생성되고, DOM에 추가되는 과정
- 클래스형 컴포넌트에서:
constructor : 컴포넌트 초기 설정. 초기 상태(state)와 인스턴스 변수를 정의함
static getDerivedStateFromProps : 부모 컴포넌트로부터 전달된 props에 따라 state를 업데이트
render : JSX를 반환하여 DOM에 렌더링
componenetDidMount : 컴포넌트가 처음 DOM에 렌더링된 이후 호출됨. API 호출, 이벤트 리스너 등록 등에 사용됨
- 함수형 컴포넌트에서:
useEffect : 마운트 후의 작업을 처리함
(2) 업데이트(Update) : 컴포넌트가 리렌더링되는 과정
- 클래스형 컴포넌트에서:
static getDerivedStateFromProps: 새로운 props에 따라 state를 업데이트
shouldComponentUpdate: 컴포넌트 리렌더링 여부를 결정(true일 때 리렌더링)
render : 컴포넌트가 업데이트될 때 다시 호출되어 DOM을 갱신
componenetDidUpdate : 컴포넌트가 업데이트된 후 호출됨
- 함수형 컴포넌트에서:
useEffect : 상태나 props 변경 시 실행 됨
(3) 언마운트(Unmount) : 컴포넌트가 DOM에서 제거되는 과정
- 클래스형 컴포넌트에서:
componentWillUnmount : 컴포넌트가 DOM에서 제거되기 직전에 호출
- 함수형 컴포넌트에서:
useEffect의 claenup 함수
'(SK쉴더스)AI 활용한 클라우드 & 보안 전문가 양성 캠프' 카테고리의 다른 글
[새싹 성동 2기] 4-3. 리액트 라우터 (1) | 2024.11.20 |
---|---|
[새싹 성동 2기] 4-2. 리액트 컴포넌트(3) (1) | 2024.11.19 |
[새싹 성동 2기] 4-2. 리액트 컴포넌트(1) (0) | 2024.11.18 |
[새싹 성동 2기] 4-1. JSX 규칙 (1) | 2024.11.18 |
[새싹 성동 2기] 4. 리액트(React) 라이브러리 (1) | 2024.11.18 |