import React, { useEffect, useState } from "react";
import useCounter from "./useCounter";
const MAX_CAPACITY = 10;
function Accommodate(props){
const [isFull,setIsFull] = useState(false);
const [count,increaseCount,decreaseCount] = useCounter(0);
useEffect(()=>{
console.log("=====================");
console.log("useEffect() is called.");
console.log(`isFull: ${isFull}`);
});
useEffect(()=>{
setIsFull(count>=MAX_CAPACITY);
console.log(`Current count value: ${count}`);
}, [count]);
return(
<div style={{padding:16}}>
<p>{`총 ${count}명 수용했습니다.`}</p>
<button onClick={increaseCount} disabled={isFull}>
입장
</button>
<button onClick={decreaseCount}>
퇴장
</button>
{isFull&&<p style={{color:"red"}}>정원이 가득찼습니다.</p>}
</div>
)
}
export default Accommodate;import React,{useState} from "react";
function useCounter(initialValue){
const [count,setCount] = useState(initialValue);
const increaseCount = ()=> setCount((count)=>count+1);
const decreaseCount = ()=> setCount((count)=> Math.max(count -1,0));
return [count,increaseCount,decreaseCount];
}
export default useCounter;
import React,{useEffect,useState,useMemo, useCallback,useRef} from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import Library from './chapter_03/Library';
import Clock from './chapter_04/Clock';
import CommentList from './chapter_05/CommentList';
import Notification from './chapter_06/Notification';
import NotificationList from './chapter_06/NotificationList';
import Accommodate from './chapter_07/Accommodate';
const root = ReactDOM.createRoot(document.getElementById('root'));
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => setCount(c => c + 1), 1000);
return () => clearInterval(interval); // 타이머 정리
}, []); // 빈 배열로 한 번만 실행
return <p>Timer: {count}s</p>;
}
function ExpensiveComponent({a,b}){
const result = useMemo(()=>{
console.log("복잡한 계산 실행");
return a+b;
},[a,b]);
return <p>Result: {result}</p>;
}
function Parent(){
const [count,setCount] = useState(0);
const handleClick = useCallback(()=>{
console.log("Button clicked");
},[]);
return(
<div>
<p>Count : {count}</p>
<button onClick={()=> setCount(c=>c+1)}>Increase</button>
<Child onClick={handleClick}/>
</div>
);
}
function Child({onClick}){
console.log("Child 렌더링");
return <button onClick={onClick}>Click me</button>;
}
function FocusInput() {
const inputRef = useRef(null);
const handleFocus = () => {
inputRef.current.focus(); // DOM 요소에 직접 접근
};
return (
<div>
<input ref={inputRef} />
<button onClick={handleFocus}>Focus Input</button>
</div>
);
}
root.render(
<React.StrictMode>
<FocusInput a={10} b={5}/>
</React.StrictMode>
);
reportWebVitals();

오늘의 React 학습 정리: 주요 Hook과 개념
1. useState: 상태 관리
컴포넌트에서 상태를 관리할 수 있게 해주는 기본 Hook.
값을 저장하고 업데이트할 때 사용.
버튼 클릭, 입력 값 변경 등 컴포넌트 내부 상태를 관리하는 데 활용.
2. useEffect: 부수효과 관리
컴포넌트가 렌더링될 때 특정 작업을 실행할 수 있도록 도와주는 Hook.
데이터 가져오기(API 호출), DOM 업데이트, 타이머 설정 등 다양한 작업에 사용.
의존성 배열을 통해 실행 시점을 제어 가능:
빈 배열([]): 컴포넌트가 처음 마운트될 때 한 번만 실행.
특정 값 의존([value]): 값이 변경될 때마다 실행.
3. useMemo: 값 메모이제이션
계산 비용이 큰 연산의 결과를 메모이제이션하여 성능을 최적화.
의존성 배열의 값이 변경되지 않는 한 이전에 계산된 값을 재사용.
복잡한 계산 로직이나 렌더링 시 반복적으로 계산되지 않도록 방지.
4. useCallback: 함수 메모이제이션
특정 함수 객체를 메모이제이션하여 동일한 함수를 재사용.
자식 컴포넌트에 전달하는 콜백 함수가 불필요하게 새로 생성되지 않도록 방지.
의존성 배열의 값이 변경되지 않는 한 동일한 함수 객체를 유지.
5. useRef: 참조 관리
DOM 요소나 렌더링과 관련 없는 값을 저장.
DOM 요소에 직접 접근하거나, 컴포넌트 간 상태 공유 없이 특정 값을 저장하는 데 사용.
상태와 다르게 값이 변경되어도 컴포넌트가 재렌더링되지 않음.
6. Custom Hook: 로직 재사용
반복적으로 사용되는 상태 관리 로직을 별도의 함수로 추출해 재사용 가능.
예를 들어, 카운터 로직을 useCounter로 구현하면, 다양한 컴포넌트에서 동일한 카운팅 로직을 쉽게 활용할 수 있음.
7. 주요 실습 내용
1) 정원 관리 시스템
최대 수용 인원을 관리하며, 초과 시 메시지를 표시.
상태와 부수효과(useState, useEffect)를 활용하여 동작 구현.
2) 타이머
1초마다 증가하는 타이머를 구현.
타이머 설정 및 해제를 useEffect로 관리.
3) 성능 최적화
복잡한 계산 로직을 useMemo로 최적화.
자식 컴포넌트의 불필요한 렌더링을 useCallback으로 방지.
4) DOM 조작
useRef를 사용해 입력 필드에 직접 포커스를 설정.
8. 오늘 배운 React의 핵심
React Hook 활용:
상태 관리와 부수효과 처리부터 성능 최적화까지 다양한 기능 학습.
성능 최적화:
useMemo와 useCallback을 통해 렌더링 최적화 기법 이해.
Custom Hook의 활용성:
공통 로직을 재사용 가능하도록 설계하는 방법 익힘.