Facebook(현재 Meta)에서 만든 Javascript 사용자 인터페이스(UI) 라이브러리이다. React 자체는 Framework라 부를 수 있는 기준인 라우팅, 상태관리 기본 제공을 충족하지 못하기에 '라이브러리'이지만, React의 생태계는 Framework이다.
SPA(Single Page Application)란?
SPA는 모던 웹의 패러다임으로, 하나의 HTML에다가 사용자가 특정 페이지를 호출할 때 그 HTML에다가 내용을 채워서 보내준다.
- 웹 앱에 필요한 모든 정적 리소스를 처음에 한번 다운로드한다.
- 페이지 간 이동 시, 페이지 갱신에 필요한 데이터만을 JSON으로 전달받아 페이지를 갱신한다.
전체적인 트래픽을 감소시킬 수 있고, 전체 페이지를 다시 렌더링하지 않고 변경되는 부분만을 갱신하므로 새로고침이 발생하지 않아 네이티브 앱과 유사한 사용자 경험을 제공할 수 있다. 이런 특징들은 SPA가 모바일 웹에 최적화 된 이유이기도 하다. 속도, 사용성, 반응성의 향상으로 더 나은 사용자 경험을 기대할 수 있다.
CSR vs SSR
- CSR(Client Side Rendering)
Javascript가 전부 다운로드 되어 리액트 애플리케이션이 정상 실행되기 전까지는 화면이 보이지 않는다. 초기 화면 로드는 느리지만, 일단 로드가 되고나면 사이트 내에서 돌아다닐 때 로드되는 과정이 없어 사용성이 좋다.- SSR(Server Side Rendering)
Javascript가 전부 다운로드 되지 않아도 일단 화면은 보이지만, 사용자가 사용할 수 없다. 렌더링이 빠른 장점이 있지만, 페이지를 이동할때마다 화면 깜빡임이 있다.
기존의 방식은 DOM을 직접 수정하는 방식이라 성능과 비용이 많이 드는 작업이다. 반면에 React는 DOM을 직접 수정하는 것이 아닌 Virtual DOM 에서 변경해야할 최소한의 부분을 검색(Compute Diff)해 그 부분만을 업데이트하고 렌더링 한다.
Virtual DOM이란?
Virtual DOM은 DOM Tree 구조와 같은 구조체의 가상의 DOM을 말한다. React는 이벤트가 발생할 때마다 Virtual DOM을 만들고, Repaint 과정에서 실제 DOM과 전후 상태를 비교, 변경이 필요한 최소한의 변경사항만 실제 DOM에 반영해, 앱의 효율성과 속도를 개선한다.
레고 블록을 조립하는 것처럼 컴포넌트들을 조합해 UI를 효과적으로 구성할 수 있고 코드의 재사용성도 증가한다. 이는 곧 개발기간 단축과 유지 보수의 용이로 이어진다.
Javascript를 확장한 문법으로 가독성이 좋고 컴파일 과정에서 문법적 오류를 인지하기 쉽다.
가장 많이 사용하는 라이브러리로 찾아볼 수 있는 자료가 많다.
Props란 부모 컴포넌트에서 자식 컴포넌트로 전달해 주는 데이터다. 읽기 전용 데이터라고 볼 수 있는데, 자식 컴포넌트에서 전달받은 Props는 변경이 불가능하고 Props를 전달해준 최상위 부모 컴포넌트만 Props를 변경할 수 있기 때문이다.
State는 현재 컴포넌트에서 생성, 변할 수 있는 데이터이다. state는 오직 state가 생성된 컴포넌트 내에서만 변경이 가능하다. 즉, State는 한 컴포넌트의 상태를 나타낸다.
React의 함수 컴포넌트에서는 State를 사용하기 위해 useState라는 훅(Hook)을 사용하는데, useState는 State 변수의 초기값을 매개변수로 전달 하여 호출하며, 결과값으로는 배열을 반환한다. 반환된 배열에서는 useState 함수를 호출할 때 설정한 초기값이 할당된 변수와 해당 변수를 수정하기 위한 Set 함수가 포함되어 있다.
데이터가 한 방향으로만 흐르고 새로운 데이터를 넣으면 처음부터 흐름이 다시 시작되는 방식으로 설계 되었고, 이를 Flux 아키텍처라고 한다.
단방향 바인딩은 데이터의 변경이 UI로 전달되어 화면을 업데이트한다. 또한 단방향 바인딩은 성능 저하 없이 DOM을 렌더링 시켜줍니다.
컴포넌트가 렌더링 될 때 특정 작업을 실행할 수 있도록 하는 Hook이다. 리액트의 useEffect 훅을 사용하면 함수 컴포넌트에서도 side effect를 사용할 수 있다.
side effect
: 함수 내 특정 동작이 함수 외부에 영향을 끼쳐, 프로그램의 동작을 이해하기 어렵게 만드는 행위
ex) 서버와의 통신, setTimeout/setInterval, 리액트 외부와 상호작용
컴포넌트는 생성(Mounting) -> 업데이트(Updating) -> 제거(Unmounting)의 생명주기를 갖는다.
생명주기 순서
- 컴포넌트가 호출되어 로드
- 컴포넌트 내부 함수 수행 - 데이터의 초기화를 수행
- return() 함수 실행 - 화면의 렌더링을 수행
- useEffect() 실행
- 조건부 수행:
5-1. useEffect() 실행 - 컴포넌트의 '변화'가 발생하는 경우 수행
5-2. useEffect() 실행 - 컴포넌트의 '소멸'이 발생하는 경우 수행
const Lifecycle = (props) => {
/**
* 2. 컴포넌트 내부 함수 수행 단계
* 컴포넌트 호출 시 가장 먼저 호출이 되는 공간
*/
console.log("해당 부분이 제일 먼저 호출");
const [info, setInfo] = useState({
userId: 'abc',
userName: 'abc',
});
/**
* 4. useEffect() 실행 단계
* 컴포넌트 내에서 렌더링이 수행된 이후에 실행이 되는 메서드
*/
useEffect(() => {
console.log("화면이 렌더링 된 이후에 바로 수행이 됨");
}, []);
/**
* 3. return() 함수 실행 단계
* 미리 구현한 HTML를 화면상에 보여주는 메서드
*/
return (
<>
{console.log("Rendering ...")}
<div>
<h1>LifeCycleTest</h1>
<div>{userInfo.userId}</div>
</div>
</>
)
};
export default Lifecycle;
3-1. Mounting - useEffect(()⇒{}, [])
3-2. Updating - useEffect(()⇒{}, [값])
3-3. Unmounting - useEffect(()⇒{ return { // }}, [값])