효율적으로 사용자 인터페이스를 만들기 위한 자바스크립트 라이브러리
이다. 컴포넌트 기반 개발
이 가능하고, 단방향 데이터 흐름을 가지
며, 가상 돔을 이용한 효율적인 업데이트
가 가능하다는 특징이 있다. 또한 Client Side Rendering을 통한 Single Page Application 개발
이 가능하다.개발을 위한 기능을 제공하는 도구
이고, 프레임워크는 개발을 위한 구조를 제공하는 도구
이다.컴포넌트 기반으로 재사용성이 뛰어나
고, 단방향 데이터 흐름을 가져 데이터를 추적하여 유지보수하는 것이 용이
하며, 가상 돔을 이용한 효율적인 업데이트가 가능
하기 때문이다. 또한 Next.js, React Native와 같은 리액트 기반 기술
의 러닝 커브를 줄일 수 있다고 생각했다.
제이쿼리
- 리액트처럼 자바스크립트의 사용성을 개선하는 라이브러리이다. 여러 브라우저에서 호환성이 뛰어나다는 장점이 있지만,
가상 돔을 사용하는 리액트보다 낮은 성능
을 보여줬고, 이와 동시에크롬의 점유율이 높아짐
에 따라서 인기가 낮아지고 있다.
리액트에서 사용하는 자바스크립트 확장 문법
으로, 자바스크립트 파일 내부에서 XML과 유사한 형태의 마크업 코드를 작성
할 수 있게 해준다. 이로 인해 마크업 파일을 분리할 필요가 없어져 가독성이 개선되고 유지보수가 용이
해진다.상태 변화를 추적하여 효율적인 업데이트를 수행
하는 실제 DOM의 복사본
이다. / 가상 돔을 통한 업데이트는 변경 사항이 적용되지 않은 가상 돔과 변경 사항이 적용된 가상 돔을 비교
함으로써, 일정 시간동안 발생한 상태 변경을 일괄 적용
(=Batch Update, Batching)할 수 있고 최소한의 변경만을 실제 DOM에 반영하여 리플로우와 리페인트를 최소화
할 수 있다.
Auto Batching
기존에는
React event handler
에서만 Batch Update가 일어났다. 그러나 React 18 이후 Auto Batching 기술이 발표되면서,Promise, 타이머 함수, Native event handler
에 모두 Batch Update가 적용되도록 개선되었다.
동적으로 렌더링되는 여러 요소에 고유값을 부여
하기 위한 프로퍼티이다.요소마다 고유한 key를 부여하여 요소를 구별
해야 한다. 그렇지 않으면 요소를 구별할 수 없어서 모든 요소를 다시 렌더링하므로 Warning이 발생
한다.CSR은 첫 단계에서 서버로부터 빈 HTML
을 전달받는다. 이후 모든 페이지에 대한 자바스크립트를 다운로드받아 실행하여 'Viewable한 상태'를 완성시키고 사용자와의 상호 작용에 따라 'interactive한 상태'까지 완성
한다. CSR은 (완전한 콘텐츠가 보이는)첫 로딩은 느리지만 그 이후 페이지를 이동할 때는 빠른 속도를 가지며, 검색 엔진 최적화에 불리
하다는 특징이 있다. / 반면 SSR은 첫 단계에서 서버로부터 해당 페이지에 대한 'Viewable한 상태'의 완전한 HTML
을 전달받는다. 이후 자바스크립트 파일을 다운로드받아 실행하여 'interactive한 상태'까지 완성
한다. SSR은 첫 로딩은 빠르지만 페이지 이동 시에는 비교적 느린 속도를 가지며, 검색 엔진 최적화에 유리
하다는 특징이 있다.
SPA(Single Page Application)
처음에
서버에서 빈 HTML를 받아온 이후 사용자와의 상호 작용에 따라 동적으로 페이지를 렌더링하는 애플리케이션
이다. /클라이언트단으로부터 필요한 데이터만을 비동기적으로 로드
하기 때문에첫 로딩을 제외한 속도가 빠르고 새로고침이 발생하지 않는다
는 장점이 있다.
구글이나 네이버 같은 사이트의 검색 엔진이 HTML 문서를 잘 분석하도록 하는 작업
을 검색 엔진 최적화라고 한다. / CSR 방식을 사용하는 사이트들은 서버로부터 빈 HTML
을 전달받기 때문에 검색 엔진에 빈 HTML이 수집되어 검색 엔진 최적화가 잘 이루어지지 않는다.Next.js와 같은 프레임워크를 이용한 SSR이나 SSG 방식
을 사용하는 것이 방법이 가장 효율적이다. / CSR 방식을 사용해야 하는 경우, react-helmet, react-snap 등의 라이브러리
를 통해 검색 엔진 최적화 성능을 높일 수 있다. 페이지 별로 메타 데이터를 설정할 수 있도록
해주는 라이브러리이고(여전히 HTML 파일은 하나), react-snap은 페이지 별로 각각의 HTML 파일을 가지도록
해주는 라이브러리이다.재사용 가능한 독립적인 단위
로, 자체적으로 상태를 가지고 이 상태에 따라 업데이트를 수행
한다.클래스 컴포넌트는 class 키워드와 extends 키워드를 통해 React.Component 객체를 상속받아 만들어지는 컴포넌트
이고, 함수 컴포넌트는 함수로 작성된 컴포넌트
이다.
클래스 컴포넌트는 constructor
를 통해 상태를 관리하고 componentDidMount, componentDidUpdate, componentWillUnmount
를 사용하여 생명 주기에 대한 동작을 정의한다. 반면 함수 컴포넌트는 useState Hook
을 통해 상태를 관리하고 useEffect Hook
을 통해 생명 주기에 대한 동작을 정의한다.
함수 컴포넌트는 Hook의 도입과 this를 사용하지 않는다는 점에서 간결한 코드
를 작성하기 유리하다. 또한 메모리를 덜 사용
한다.
super(클래스 컴포넌트)
부모 클래스의 생성자(ex. React.Component 객체의 constructor)를 호출하고 실행하는 메서드.
super를 호출하기 전에는 this를 사용할 수 없다.
render(클래스 컴포넌트)
JSX를 정의하고 반환하는 메서드.
forceUpdate(클래스 컴포넌트)
강제 업데이트 메서드.
컴포넌트는 마운트, 업데이트, 언마운트라는 생명주기를 가진다. 마운트는 컴포넌트가 실행되어 DOM에 등록되는 시점
이고, 업데이트는 컴포넌트에 변경이 생겨 DOM에 변경 사항을 적용하는 시점
이고, 언마운트는 컴포넌트가 종료되어 DOM에서 제거되는 시점
이다.
컴포넌트에서 업데이트가 일어나는 경우
- state나 props가 변경될 때
- 부모 컴포넌트가 리렌더링될 때
- forceUpdate()로 강제 업데이트될 때 (클래스 컴포넌트에서만)
컴포넌트를 인자로 받아 새로운 컴포넌트를 반환하는 컴포넌트
이다. 여러 컴포넌트에서 재사용되는 로직을 추상화
할 수 있다.부모 컴포넌트에서 자식 컴포넌트로 전달하는 데이터
이고, state는 컴포넌트 내부에서 관리하는 동적인 데이터
이다. / 자식 컴포넌트에서 props는 Read-Only, 즉 수정할 수 없다. 변경되는 것은 state이다.단방향 데이터 플로우
를 가진다는 것을 보여준다.)상위 컴포넌트에서 타겟 컴포넌트로 props를 전달할 때, 모든 중간 컴포넌트에서 props를 내려주는 비효율적인 작업
을 의미한다. / 이러한 문제는 전역 상태 관리 라이브러리
를 사용하여 해결할 수 있다.
자식 컴포넌트의 상태를 부모 컴포넌트로 전달하는 방법
부모 컴포넌트에서
props를 통해 상태를 변경하는 함수를 자식 컴포넌트에 전달
하고, 자식 컴포넌트에서전달받은 함수를 사용하여 부모 컴포넌트의 상태를 변경
하는 방식으로 전달이 가능하다.
리액트가 상태 변화를 감지
하기 위해서는 상태를 변경하고자 하는 데이터의 불변성을 유지
해야 한다. / 원시 타입의 값은 불변성을 가지므로 상태 변화를 잘 감지
하지만, 참조 타입의 값은 불변성을 가지지 않아 상태 변화를 감지할 수 없
다. 그러므로 참조 타입인 상태를 변경할 때는 스프레드 연산자 혹은 배열이나 객체의 메서드(Array.from, Array.slice, Object.assign ...)를 통해 '얕은 복사'를 하고, 이 복사본을 통해 상태를 변경
해야 한다.
깊은 복사
데이터 내부에 또 다른 참조 타입 데이터를 가지는 경우
,JSON 메서드(JSON.stringify & JSON.parse) 혹은 lodash나 immer 등의 라이브러리를 통해 '깊은 복사'를 하고, 이 복사본을 통해 상태를 변경
해야 한다.
함수 컴포넌트에서 클래스 컴포넌트의 기능을 사용하기 위한 함수
이다.상태 관리를 위한 훅
이다. useState는 비동기적으로 상태를 변경
하고, 일정 시간(16ms)동안 변경된 상태를 일괄 적용하는 Batch Update
가 수행된다.
왜 state를 직접 변경하지 않고, useState를 사용해야 하는가
내부적으로 render 함수가 호출되어 렌더링이 진행되기 때문이다.
클래스 컴포넌트의 생명주기 메서드를 대체할 수 있는 훅
이다. 의존성 배열 없이 사용한 useEffect의 콜백 함수
는 componentDidMount와 componentDidUpdate를 합친 것처럼 동작한다. 빈 의존성 배열을 가지는 useEffect의 콜백 함수
는 componentDidMount처럼 동작하는 한편, return문에는 componentWillUnmount처럼 동작하는 정리 함수를 정의할 수 있다. 의존성 배열에 특정값이 들어있는 useEffect의 콜백 함수
는 componentDidMount처럼 동작하는 동시에 의존성 배열에 지정된 값이 변경되었을 때는 componentDidUpdate처럼 동작한다.페인트 작업 전(= 돔 업데이트 직후)에 실행되는 훅
으로, 페인트 작업 이후 실행되는 useEffect가 문제를 일으키는 경우에 대안으로 사용
할 수 있다. useEffect 내부에 DOM에 영향을 주는 코드가 있을 경우 화면의 깜빡임이 발생
하는데, useLayoutEffect로 변경하면 깜빡임이 발생하지 않음)복잡한 상태 관리 로직을 간결하게 작성하도록 도와주는 훅
이다.(state와 action 객체를 파라미터로 받는)리듀서 함수를 switch-case문으로 정의
한다. 그리고 useReducer의 파라미터로 리듀서 함수와 state의 초기값
을 넣어 호출하면 state와 dispatch 함수
를 반환하는데, dispatch 함수에 action 객체의 타입
을 전달하여 상태를 쉽게 관리할 수 있다.Context API를 통해 상태를 전역적으로 관리할 수 있도록 도와주는 훅
이다. 컨텍스트 객체를 생성하고 전역에서 관리할 상태들을 정의
한다. 그리고 컨텍스트 객체의 Provider를 통해 공유할 상태를 value에 명시하고 컨텍스트 객체를 공유할 컴포넌트들을 감싸
면, 각 컴포넌트에서 useContext를 통해 컨텍스트 객체에 명시한 상태에 접근
할 수 있다.)리액트의 라이프 사이클을 고려하여 DOM에 접근하기 위한 훅
이다. DOM API를 이용하여 DOM을 직접 조작하는 것은 리액트 라이프 사이클과 관련이 없
기 때문에, useRef를 사용하여 DOM을 조작해야 한다.참조 객체(ref)를 생성
하고 DOM 요소의 ref 속성을 통해 DOM 요소와 참조 객체를 연결
하여 참조 객체에 ‘실제 DOM 요소의 참조'를 저장
한다. 이를 통해 참조 객체의 current 프로퍼티를 통해 DOM을 조작
할 수 있게 된다.)렌더링에 직접 관여하지 않는다
. 따라서 즉시 렌더링에 관여하지 않을 상태 관리
를 위해 사용할 수 있다. (useRef를 사용한 변경 사항은 렌더링 시점에 적용!)DOM 요소의 ref 속성
에는 참조 객체 대신 Callback Ref라고 부르는 콜백 함수
를 전달할 수도 있다. 이 작업을 통해 해당 DOM 요소가 마운트되거나 언마운트될 때마다 실행될 동작을 정의
할 수 있다. (즉 useEffect의 역할 가능!)자식 컴포넌트에서 참조 객체를 전달받
을 수 있고, useImperativeHandle을 통해 자식 컴포넌트에서 부모 컴포넌트로 함수를 전달
할 수 있다.useRef를 통해 참조 객체를 생성하고 자식 컴포넌트의 ref 속성을 통해 자식 컴포넌트와 참조 객체를 연결
하면, 자식 컴포넌트는 forwardRef를 통해 참조 객체를 받아올 수 있
다. 그리고 (forwardRef 내부에서) useImperativeHandle의 첫 번째 인자에 '부모로부터 전달된 참조 객체'를, 두 번째 인자에 '콜백 함수'를 넣고, 콜백 함수에서 '부모 컴포넌트로 전달할 자식 컴포넌트의 함수'를 반환
하면 부모 컴포넌트에서도 current 속성을 통해서 자식 컴포넌트의 함수를 사용
할 수 있다.)이전에 사용한 결과값
을 재사용하는 훅이다.첫 번째 파라미터로 콜백 함수, 두 번째 파라미터로 의존성 배열을 저장
한다. 콜백 함수에는 메모이제이션할 값을 계산하는 로직을 정의하고, 의존성 배열의 값이 변경된다면 콜백 함수를 다시 실행해서 결과값을 업데이트하고 변경되지 않는다면 기존 결과값을 재사용한다.)이전에 사용한 함수
를 재사용하는 훅이다.첫 번째 파라미터로 콜백 함수, 두 번째 파라미터로 의존성 배열을 저장
한다. 의존성 배열의 값이 변경된다면 새로운 함수를 생성하여 사용하고 변경되지 않는다면 기존의 함수를 재사용한다.)useState와 useEffect같은 Hook을 사용하여 재사용이 가능하도록 만든 함수
이다. 'use'라는 이름으로 시작
하고 상태 값과 해당 상태를 업데이트하는 함수를 반환
하는 특징을 지닌다.코드를 여러 개의 작은 chunk로 나누어 해당 기능이 필요한 시점에 해당 chunk를 로드
하는 렌더링 최적화 기술이다. / 비동기 로딩
을 위해 Dynamic import와 React.lazy를 사용하고 로딩 중임을 표시
하기 위해 Suspense를 함께 사용한다.
Code Splitting 동작 방식
Dynamic import를 통해 코드를
여러 개의 모듈
로 나눈다. 이 모듈들은 bundle.js 파일에 저장되는 것이 아니라,별도의 chunk 파일로 저장
되며, 이 chunk 파일은해당 모듈이 필요한 시점에 비동기적으로 로드
된다. / 한편 Dynamic import는 Promise를 반환하는데, React.lazy를 사용하면Promise를 직접 처리하지 않고 내부적으로 처리하도록 하여 비동기 로딩을 쉽게 완료
할 수 있다. 또한 Suspense의 fallback 속성을 통해로딩 중일 때 표시할 컨텐츠를 지정
할 수 있다.
상태 관리 라이브러리
이다.하나의 중앙 집중화된 Store 객체에 상태를 저장하고 관리하는 상태 관리 라이브러리
이다. / Redux Toolkit과 미들웨어(Redux Thunk, Redux Saga, Redux-observable)를 사용하여 개발 생산성을 향상
(리덕스 사용성 개선, 비동기 작업의 효율적 관리)시킬 수 있고, 안정적인 DevTool을 가지고 있기 때문에 대규모 상태를 관리에 용이
하다. 다만 코드의 양이 많아 보일러플레이트 코드가 발생
하게 된다는 단점이 존재한다.atoms에서 상태를 저장하고 관리하는 Context API 기반 상태 관리 라이브러리
이다. / 비교적 간단한 구조롤 가지기 때문에 코드의 양을 줄일 수 있
지만, 대규모 상태를 관리할 때는 Rudux에 비해서는 안정성이 떨어진다
.상태를 전역에서 관리
하며 selector를 통해 atom에 저장된 상태를 새로운 값으로 계산
할 수 있다. RecoilRoot를 통해 Recoil State를 공유할 컴포넌트들을 감싸고
각 컴포넌트에서는 useRecoilState 등의 메서드를 통해 Recoil State에 접근
할 수 있다.)서버 상태를 가져와 관리하는 것에 중점을 둔 라이브러리
이다. Redux, Recoil 등은 서버 상태와 동기화되지 않기 때문에 웹 스토리지 등에서 따로 관리해야하는데, React-Query, SWR 등을 사용하면 이러한 불편함을 해소할 수 있다.먼저 서버의 상태(데이터)를 가져온 후 데이터를 패칭/캐싱/동기화하는 라이브러리
이다.다양한 기능을 지원
한다.)React-Query의 기능
- 탭을 이동했다가 다시 돌아왔을 때, 데이터를 다시 보여준다.
- 변경된 서버 데이터를 다시 불러온다. (setInterval 대체 가능, 양방향은 아니기 때문에 Web Socket은 대체가 어려움)
먼저 캐시에서 데이터를 반환받은 후, 서버에 데이터를 가져오는 요청을 보내고 최신 데이터를 제공받는 React Hooks 라이브러리
이다. 간단하게 사용 가능
하다.)서버의 데이터를 읽어와 fetching하는 훅
으로, HTTP GET 요청 시 주로 사용한다. / (첫 번째 인자에는 고유한 queryKey
, 두 번째 인자에는 Promise를 반환하는 queryFn
을 넣고, 세 번째 인자에는 options
을 넣을 수 있다. (querykey는 응답 데이터를 캐싱하기 위해, queryFn은 쿼리 요청을 수행하기 위해 필요하다.) 그러면 data, isLoading, isError, refetch 등
다양한 값을 반환받을 수 있는데, 이를 통해 서버 데이터와 관련된 작업
을 할 수 있다.)서버의 데이터를 변경하는 훅
으로, HTTP POST, PUT, PATCH, DELETE 요청 시 주로 사용한다. / (인자로 Promise를 반환하는 mutationFn
을 넣어주면 mutate
함수를 반환받는데, mutationFn은 mutate의 인자로 전달된다. 그러므로 mutationFn에는 나중에 실행할 내용을 정의
하고, mutate를 통해 실행
된다. (mutationFn은 queryFn과 달리 곧바로 실행되지 않는다.) 한편 두 번째 인자에는 options
을 넣을 수 있는데, onSuccess, onError, onSettled를 통해 추가 로직을 작성
할 수도 있다.)연속으로 다음 데이터를 가져오는 훅
이다. / (첫 번째 인자는 고유한 queryKey
, 두 번째 인자에는 Promise를 반환하는 queryFn
을 넣고, 세 번째 인자인 options
에서는 getNextPageParam을 통해 다음 페이지 호출에 필요한 파라미터를 정의
할 수 있다. (다른 작업도 가능!) 그러면 data, isLoading, isError, fetchNextPage, hasNextPage 등
다양한 값을 반환받을 수 있는데, 이 데이터를 통해 무한 스크롤, 페이지네이션 등
을 쉽게 구현할 수 있다.)데이터를 fresh한 상태로 유지하는 시간
이다. staleTime 동안에는 캐시에 저장된 데이터
를 가져오고, staleTime이 경과하고 특정 조건(백그라운드 상태에서 다시 focus될 때 등)이 만족하면 새로운 데이터
를 가져온다. / (기본값 0)쿼리 결과를 캐시에 저장하는 시간
이다. / (기본값 5분)form 요소의 값에 접근하기 위한 방식
으로, 제어 컴포넌트는 useState를 사용하여 event.target.value를 상태에 저장하여
값에 접근하고, 비제어 컴포넌트는 useRef를 사용하여 DOM 요소에 접근하여 ref.current.value를 통해
값에 접근한다. 높은 신뢰도의 값
을 가지며 업데이트할 때마다 매번 렌더링이 발생
(실시간 유효성 검사 가능)한다는 특징을 가진다. (너무 잦은 렌더링은 debounce, throttle
을 통해 방지할 수 있음!)React를 사용하여 모바일 애플리케이션을 개발하기 위한 프레임워크
이다. 하나의 코드로 iOS와 Android에 대한 애플리케이션을 개발할 수 있는 '크로스 플렛폼 앱' 개발 언어
이고, 이는 네이티브 앱에 준하는 성능
을 보여줄 수 있다.React와의 공통점
- React의 핵심 개념인
Component, JSX, props, state
를 사용한다.
React와의 차이점
- 가상 DOM을 사용하지 않고,
AppRegistry
를 사용한다.- HTML 문법을 사용하지 않고,
Component
만을 사용한다.- 기존의 CSS를 지원하지 않고, 자바스크립트 파일 안에서
StyelSheet
를 사용한다.