[React] 개념

2025. 12. 23. 22:19·공부일기../리액트

아 계속 헷갈려서 비슷한 내용을 계속계속 정리하고 읽어보겠슴미다.. 


1. React의 동작 원리와 기본 구조

1-1. SPA(Single Page Application)의 개념

React는 단일 페이지 애플리케이션(SPA) 방식으로 동작한다. 기존 웹 애플리케이션과 달리, 실제로 존재하는 HTML 파일은 딱 하나뿐이며, JavaScript가 동적으로 화면의 내용을 변경하는 방식으로 작동한다.

사용자가 다른 페이지로 이동하는 것처럼 보이지만, 실제로는 서버에 새로운 HTML을 요청하지 않고 클라이언트 측에서 JavaScript가 DOM을 조작하여 화면을 갱신한다.

1-2. 프로젝트의 기본 파일 구조

React 프로젝트를 생성하면 기본적으로 다음과 같은 구조를 가진다. public 폴더에는 index.html 파일이 위치하며, 이것이 애플리케이션의 유일한 HTML 파일이다. src 폴더에는 index.js가 진입점(entry point)으로 존재하고, App.js가 메인 컴포넌트로서 애플리케이션의 루트 역할을 수행한다.

그리고 pages 폴더에는 각 라우트에 해당하는 페이지 컴포넌트들을 배치하고, components 폴더에는 재사용 가능한 컴포넌트들을 구성한다.

1-3. 렌더링 메커니즘

index.html 파일에는 `<div id="root"></div> ` 라는 빈 컨테이너만 존재한다. index.js 파일에서 ` ReactDOM.createRoot() 메서드 ` 를 사용하여 이 root div를 찾고, 그 안에 React 컴포넌트 트리를 렌더링한다. 이때 root.render(<App />)를 호출하면 App 컴포넌트가 root div 내부에 삽입되고, 이후 모든 UI 변경은 JavaScript를 통해 이루어진다.

1-4. 빌드 프로세스

개발 중에는 여러 개의 JavaScript 파일로 나뉘어 있지만, npm run build 명령을 실행하면 모든 JavaScript 코드가 하나의 번들 파일로 합쳐진다. 빌드된 결과물은 build 폴더에 생성되며, index.html 파일에는 번들된 JavaScript 파일을 참조하는 script 태그가 자동으로 추가된다. 이렇게 생성된 정적 파일들을 웹 서버에 배포하여 서비스한다.

 

 

 

2. React Router를 통한 라우팅

2-1. React Router DOM의 역할

react-router-dom 라이브러리는 React에서 클라이언트 사이드 라우팅을 구현하기 위해 사용된다. 이 라이브러리는 URL 변경을 감지하고, 해당 URL에 맞는 컴포넌트를 렌더링하는 역할을 수행한다. 실제로 서버에 새로운 페이지를 요청하지 않고, URL만 변경한 후 JavaScript로 화면을 업데이트하는 방식이다.

2-2. BrowserRouter 컴포넌트

BrowserRouter는 라우팅 기능을 활성화하기 위한 최상위 컴포넌트다. 애플리케이션의 루트 레벨에서 전체 앱을 감싸는 형태로 사용되며, HTML5 History API를 활용하여 URL을 관리한다. 이 컴포넌트로 감싸진 하위 컴포넌트들은 라우팅 관련 기능을 사용할 수 있게 된다.

2-3. Routes와 Route 컴포넌트

React Router v6에서는 Routes 컴포넌트가 여러 Route 컴포넌트를 감싸는 구조를 사용한다. Route 컴포넌트는 path prop으로 URL 경로를 지정하고, element prop으로 해당 경로에 렌더링할 컴포넌트를 지정한다. Routes 컴포넌트는 여러 Route 중에서 현재 URL과 일치하는 첫 번째 Route만 렌더링하는 역할을 한다.

이전 버전인 React Router v5에서는 Switch 컴포넌트를 사용했으며, component prop으로 컴포넌트를 전달했다. v6에서는 이것이 Routes와 element로 변경되었다. Routes 컴포넌트가 없으면 URL이 중복으로 매칭될 경우 여러 컴포넌트가 동시에 렌더링될 수 있기 때문에, 반드시 사용해야 한다.

2-4. 동적 라우팅

URL 파라미터를 사용하여 동적 라우팅을 구현할 수 있다. path="/user/:id"와 같이 콜론을 사용하면 해당 부분이 변수로 작동한다. 컴포넌트 내부에서는 useParams 훅을 사용하여 URL 파라미터 값을 추출할 수 있다. 예를 들어 /user/123으로 접근하면 id 값이 123이 된다.

 

 

 

3. Context Provider 패턴

3-1. CookiesProvider의 개념

react-cookie 라이브러리에서 제공하는 CookiesProvider는 Context API 패턴을 활용한 컴포넌트다. 이 컴포넌트를 최상위에 배치하면, 하위의 모든 컴포넌트에서 쿠키 관련 기능을 사용할 수 있게 된다. React의 Context는 props를 통해 데이터를 전달하지 않고도, 컴포넌트 트리 전체에서 데이터를 공유할 수 있는 메커니즘이다.

3-2. Provider 사용 방법

Provider는 일반적으로 애플리케이션의 루트 레벨에서 사용된다. 예를 들어 CookiesProvider로 앱 전체를 감싸면, 내부의 모든 컴포넌트에서 useCookies 훅을 사용하여 쿠키를 읽고 쓸 수 있다. 마치 의존성 주입 패턴처럼, 필요한 기능을 전역적으로 제공하는 방식이다.

3-3. 여러 Provider의 중첩

실제 프로젝트에서는 여러 Provider를 중첩하여 사용하는 경우가 많다. CookiesProvider, BrowserRouter, 인증 관련 Provider, 테마 Provider 등을 순차적으로 중첩하면, 각 Provider가 제공하는 기능들을 애플리케이션 전체에서 사용할 수 있다. 중첩 순서는 일반적으로 의존성이 적은 것부터 많은 순서로 배치한다.

 

 

 

4. useState Hook

4-1. 상태 관리의 필요성

React 컴포넌트에서 일반 변수를 변경해도 화면이 다시 렌더링되지 않는다. 화면을 갱신하려면 React에게 "이 값이 변경되었으니 화면을 다시 그려야 한다"고 알려야 하는데, 이를 위해 useState 훅을 사용한다. useState는 상태 값과 그 값을 변경하는 함수를 배열 형태로 반환한다.

4-2. useState의 기본 사용법

` const [state, setState] = useState(initialValue) 형태 ` 로 사용한다.

첫 번째 요소는 현재 상태 값이고, 두 번째 요소는 상태를 업데이트하는 함수다. setState 함수를 호출하면 상태가 변경되고, React는 자동으로 해당 컴포넌트를 다시 렌더링한다. 초기값은 useState의 인자로 전달하며, 숫자, 문자열, 객체, 배열 등 모든 타입이 가능하다.

4-3. 상태 업데이트의 특징

상태 업데이트는 비동기적으로 처리된다. (렌더링 자체가 비용이 많이드는거라 함수끝날때 한방에 렌더링하느라 즉시즉시 방영이 안된다고 배움..) setState를 호출한 직후에 상태 값을 확인하면 아직 변경되지 않은 값이 출력될 수 있다.

또한 이전 상태를 기반으로 새 상태를 계산해야 할 때는 함수 형태로 업데이트해야 한다. 예를 들어 setCount(count + 1) 대신 ` setCount(prev => prev + 1) ` 을 사용하면 최신 상태를 보장받을 수 있다.

4-4. 객체와 배열 상태 관리

객체나 배열을 상태로 관리할 때는 불변성을 유지해야 한다. 기존 객체를 직접 수정하는 대신, 새로운 객체를 생성하여 전달해야 React가 변경을 감지하고 리렌더링한다. 스프레드 연산자를 사용하여 setState({...state, key: newValue})와 같이 업데이트하거나, 배열의 경우 map, filter, concat 등의 메서드를 활용한다.

 

 

 

5. useEffect Hook

5-1. 부수 효과(Side Effect) 처리

useEffect는 컴포넌트가 렌더링된 후 특정 작업을 수행하기 위해 사용하는 훅이다. API 호출, 타이머 설정, DOM 조작, 이벤트 리스너 등록 등 React의 데이터 흐름에 직접적으로 속하지 않는 작업들을 처리한다. useEffect는 컴포넌트의 라이프사이클과 연동되어 특정 시점에 코드를 실행할 수 있게 해준다.

5-2. 의존성 배열의 역할

useEffect의 두 번째 인자로 의존성 배열을 전달한다. 빈 배열([])을 전달하면 컴포넌트가 마운트될 때 한 번만 실행된다. 배열에 특정 값을 넣으면 해당 값이 변경될 때마다 effect가 재실행된다. 의존성 배열을 생략하면 모든 렌더링마다 effect가 실행되는데, 성능 문제를 일으킬 수 있어 권장되지 않는다.

5-3. 컴포넌트 마운트 시 실행

빈 의존성 배열을 사용하면 컴포넌트가 처음 화면에 나타날 때 딱 한 번만 실행된다. 초기 데이터를 불러오거나 외부 라이브러리를 초기화할 때 유용하다. 예를 들어 사용자 정보를 가져오는 API를 호출하거나, 로그인 상태를 확인하는 로직을 여기에 작성한다.

5-4. 특정 값 변경 감지

의존성 배열에 상태나 props를 포함하면, 해당 값이 변경될 때마다 effect가 실행된다. 검색어가 변경될 때마다 API를 호출하거나, 사용자 ID가 바뀔 때마다 새로운 데이터를 가져오는 경우에 사용한다. React는 얕은 비교를 통해 의존성의 변경을 감지하므로, 객체나 배열의 경우 참조가 변경되어야 effect가 재실행된다.

5-5. cleanup 함수

useEffect는 정리(cleanup) 함수를 반환할 수 있다. 이 함수는 컴포넌트가 언마운트되거나 effect가 재실행되기 전에 호출된다. 타이머를 정리하거나, 이벤트 리스너를 제거하거나, WebSocket 연결을 종료하는 등의 작업을 여기서 수행한다. cleanup 함수를 제대로 작성하지 않으면 메모리 누수가 발생할 수 있다.

 

 

 

6. 이벤트 핸들링

6-1. onClick 이벤트의 기본

React에서 onClick prop은 함수를 전달받는다. 주의할 점은 함수 자체를 전달해야 하며, 함수의 실행 결과를 전달하면 안 된다는 것이다. onClick={handleClick}은 맞는 문법이지만, `onClick={handleClick()}은 렌더링 시점에 함수가 즉시 실행`되어 버린다. 의도하지 않은 동작을 유발할 수 있다. (무한 렌더링 어쩌고 에러..나옴) 

6-2. 파라미터 전달 방법

이벤트 핸들러에 파라미터를 전달하려면 화살표 함수로 감싸야 한다. onClick={() => handleClick(param)}처럼 작성하면, 클릭 시점에 화살표 함수가 실행되고 그 안에서 handleClick이 파라미터와 함께 호출된다. 일반적이고 가장 직관적인 방법이다.

6-3. 함수를 반환하는 패턴

또 다른 방법으로 함수를 반환하는 함수를 작성할 수 있다. ` const handleClick = (param) => { return () => { /* 로직 */ } } ` 와 같이 정의하면, ` onClick={handleClick(param)}로 사용 ` 할 수 있다. 이 경우 렌더링 시점에 handleClick(param)이 실행되어 함수를 반환하고, 그 반환된 함수가 onClick에 등록된다.

6-4. 이벤트 객체 접근

이벤트 핸들러는 자동으로 이벤트 객체를 인자로 받는다. 파라미터와 함께 이벤트 객체도 사용하려면 ` onClick={(e) => handleClick(param, e)}처럼 작성 ` 한다. 이벤트 객체를 통해 preventDefault()로 기본 동작을 막거나, stopPropagation()으로 이벤트 전파를 중단할 수 있다.

6-5. 리스트 렌더링에서의 이벤트 처리

배열을 순회하며 렌더링할 때 각 아이템에 고유한 이벤트 핸들러를 연결해야 하는 경우가 많다. map 함수 내부에서 화살표 함수를 사용하여 각 아이템의 ID나 데이터를 이벤트 핸들러에 전달한다. 이때 key prop을 반드시 설정하여 React가 각 엘리먼트를 구분할 수 있도록 해야 한다.

 

 

 

7. 템플릿 리터럴 문법

7-1. 문자열 보간의 필요성

JavaScript에서 문자열과 변수를 결합할 때 기존에는 + 연산자를 사용했다. 하지만 이 방식은 코드가 길어지면 가독성이 떨어지고 실수하기 쉽다. ES6부터 도입된 템플릿 리터럴은 이러한 문제를 해결하는 더 나은 방법을 제공한다.

7-2. 백틱과 달러 기호 문법

템플릿 리터럴은 작은따옴표나 큰따옴표 대신 백틱()을 사용한다. 백틱은 키보드에서 숫자 1 왼쪽, Tab 키 위에 위치한다. 변수나 표현식을 문자열에 포함시키려면 ${expression}` 형태로 작성한다. 달러 기호와 중괄호 사이에는 모든 JavaScript 표현식이 들어갈 수 있다.

7-3. 동적 URL 생성

React에서 API를 호출할 때 템플릿 리터럴을 자주 사용한다. 사용자 ID를 포함한 URL을 만들 때 fetch(`/api/user/${userId}`)처럼 작성하면 코드가 훨씬 명확해진다. 쿼리 파라미터가 여러 개인 경우에도 `/api/search?q=${keyword}&page=${page}`와 같이 간결하게 표현할 수 있다.

7-4. 표현식과 함수 호출

템플릿 리터럴 내부에서는 단순 변수뿐 아니라 계산식이나 함수 호출도 가능하다. `총액: ${price * quantity}원`처럼 산술 연산을 수행하거나, `결과: ${getData()}`처럼 함수를 호출할 수 있다. 삼항 연산자를 사용한 조건부 표현도 가능하다.

7-5. 여러 줄 문자열

템플릿 리터럴은 개행 문자를 자연스럽게 처리한다. 백틱 사이에서 Enter 키를 누르면 실제로 줄바꿈이 포함된 문자열이 생성된다. HTML 템플릿이나 긴 텍스트를 작성할 때 특히 유용하다. 별도의 이스케이프 시퀀스 없이 자연스러운 형태로 여러 줄의 문자열을 작성할 수 있다.

7-6. 보안 고려

사용자 입력값을 템플릿 리터럴에 포함시킬 때는 주의가 필요하다. 특히 HTML 문자열을 생성하는 경우 XSS 공격에 취약할 수 있다. React는 기본적으로 문자열을 이스케이프 처리하여 안전하게 렌더링하지만, dangerouslySetInnerHTML을 사용할 때는 주의가 필요하다. 신뢰할 수 없는 데이터는 반드시 검증하고 정제한 후 사용해야 한다...~ 

 

 

'공부일기.. > 리액트' 카테고리의 다른 글

[리액트] React 컴포넌트의 기본 구조  (0) 2025.11.26
'공부일기../리액트' 카테고리의 다른 글
  • [리액트] React 컴포넌트의 기본 구조
s0-0mzzang
s0-0mzzang
공부한것을 기록합니다...
  • s0-0mzzang
    승민이의..개발일기..🐰
    s0-0mzzang
  • 전체
    오늘
    어제
    • 전체~ (108)
      • 마음가짐..! (10)
      • 공부일기.. (76)
        • weekly-log (6)
        • Spring (19)
        • Java (18)
        • DataBase (10)
        • git (2)
        • JPA (6)
        • kafka (1)
        • Backend Architecture (3)
        • Troubleshooting (삽질..ㅋ) (2)
        • Cloud (1)
        • Docker (2)
        • 알고리즘 (1)
        • 리액트 (2)
        • Infra (3)
      • 하루일기.. (22)
        • 그림일기 (8)
        • 생각일기 (14)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
  • 공지사항

  • 인기 글

  • 태그

    spring boot
    JPA
    자바
    다짐
    SpringBoot
    리팩토링
    swagger
    TDD
    Paging
    MySQL
    React
    StringTokenizer
    항해플러스
    인프라 기초
    spring
    ADC 환경
    항해99
    스프링부트
    ERD
    BufferedReader
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
s0-0mzzang
[React] 개념
상단으로

티스토리툴바