리액트 미래
Last updated
Last updated
새로운 Hook, API, 리엑트 컴파일러, 리엑트 서버 컴포넌트
useMemo
, useCallback
, memo
→ React Compiler
forwardRef
→ ref
is a prop
React.lazy
→ RSC
, promise-as-child
useContext
→ use
(Context)
throw promise
→ use
(promise)
<Context.Provider>
→ <Context>
시간이 걸릴 수 있는 상태 업데이트에 대기 표시
해당 훅을 활용해서 비동기로 데이터를 가져오는 동안 로딩 인디케이터나 플레이스홀더의 렌더링을 관리할 수 있음
직접 대기/로딩 상태 속성을 만들고 관리하지 않아도 된다.
전환 진행 여부를 나타내는 '대기' 플래그를 제공함
폼 액션의 결과에 기반해 상태를 업데이트 가능
매개변수
하나의 액션 함수: 이 함수는 폼 액션이 트리거되면 실행됨
하나의 초기 상태 객체: 사용자 상호작용이 일어나기 이전의 시작 상태를 설정
(옵션) 하나의 영구 링크: 이 링크는 이 폼이 수정할 고유한 페이지 URL을 가리킴
반환값 (튜플)
폼의 현재 상태
폼 액션을 트리거하는 함수
액션의 대기 여부를 나타내는 하나의 불리언값
<form>
태그는 이제action
prop을 가짐폼이 제출되었을 때 트리거되는 액션 함수
중첩된 컴포넌트 안에서의 폼 제출로부터 상태 정보에 접근할 수 있도록 디자인됨 (useContext 같은 너낌)
Context API를 사용하여도 폼 상태나 다른 데이터를 자손으로 전달할 수 있긴하지만 "action은 이런식으로 사용하라"라고 리엑트답지 않게 만들어둔것 같다.
상위에서 <form action={action}>
, 하위에서 상위 액션의 상태를 가져오기 위해 사용되는 훅
useFormStatus
를 사용하면 직접 컨텍스트를 설정하지 않고 폼과 관련된 상태 관리를 직접적으로 간소화 가능
낙관적 업데이트란 비동기 조작과 UI 업데이트가 해당 조작의 실제 성공을 확인하기 전 이미 성공한것으로 가정
사용자 경험 향상 기법 중 하나
사용자 인터렉션 후 서버 응답을 기다리지 않고 결과를 사용자에게 즉각적으로 반영하는 것
업데이트가 종료되거나, 에러가 발생하면 리엑트는 자동으로 템플릿에서 사용된 optimisticMessage
를 message
prop의 값으로 바꾼다.
컨텍스트, 프로미스 같은 리소스로부터 값을 읽을 수 있는 다양한 방법 제공
<Context.Provider> 를 사용하지 않고 <Context> 를 직접 렌더링할 수 있게 변경됨
더이상 컨텍스트 값을 읽기위해 useContext
훅을 사용하지 않고 use()
사용
use()
는 서스펜스 및 에러바운더리와 매끄럽게 통합되어 프로미스를 읽을 수 있음
use()는 기존 리엑트 훅의 규칙과 달리 조건문이나 반복문 내부에서도 사용 가능
리액트 팀이 만든 실험적 컴파일러
최적화 프로세스를 자동화함으로써 앱 성능을 크게 개선하는것을 목적으로 함
성능 튜닝의 책임을 오롯이 개발자가 지는게 아닌 프레임워크도 어느정도 지는 식 (패러다임 이동을 의미)
컴포너트가 상태 및 props를 사용하는 것을 분석하여 효과적으로 리렌더링을 최적화함
실제로 변경되는 부분을 의존하는 컴포넌트들만 리렌더링하도록 지능적으로 결정
무엇을 메모화해야하는지에 대한 의사 결정을 자동화!
최소한의 노력으로 최소한의 성능 보장
가장 큰 영향을 미치는 부분에 메모이제이션이 정밀하고 효율적으로 적용되는 것을 보장
리엑트 컴파일러는 useEffect
안에서의 자동 메모이제이션을 처리하지 않음 (연구 및 개발은 현재 진행형이라고 함)
리엑트 컴파일러의 메모화는 여러 컴포넌트나 훅에서 공유되지 않음
리액트를 사용하는 개발자들은 memo, useMemo, useCallback 을 사용해서 불필요한 리렌더링, 계산을 방지하였는데 이 기법들은 효과적이지만 개발자가 직접 무엇을 언제 메모화할것인지 결정해야만 했음
이 수동 프로세스는 시간도 들고 휴먼에러(실수)가 발생될 수 있는 여지가 있고, 잘못 사용하면 성능을 저하시킬수 있었음
값비싼 함수 호출의 결과를 저장한 뒤 동일한 입력이 발생했을 때 캐시해 둔 결과를 반환함으로써 컴퓨터 프로그램의 속도를 높임
선언적 모델
컴포넌트 기반 아키텍처를 위한 DOM의 직접적인 조작을 추상화함으로써 개발자들은 UI를 일련의 명령적 업데이트가 아닌 상태의 반영으로 생각할 수 있게 됨
멘탈 모델, 특히 앱 복잡성이 증가할 때의 멘탈 모델을 크게 단순화시켰음
사고방식
useEffect
의 경우 의존성 배열에 의해 본질적으로 메모화되고 컴포넌트가 마운트 된 뒤 한 번만 실행되는것이 보장됨
memo
의 경우 컴포넌트를 메모화하여 부모가 리렌더링되었을 때가 아닌 각 컴포넌트의 속성이 변경되었을 때만 리렌더링되는것을 보장
useMemo
는 컴포넌트 안의 모든 계산된 값을 메모화할 수 있음
useCallback
은 컴포넌트 안의 함수 참조를 메모화
컴포넌트 내부에서 사용되는 값비싼 외부 함수의 메모이제이션도 해결함 (컴포넌트 외부에서 선언된 함수ㅇㅇ)
함수 자체를 메모이제이션 하는것은 아님
리엑트는 컴포넌트와 훅만 메모화함
함수 호출을 메모화함
리엑트 컴파일러의 메모화는 다른 컴포넌트나 훅에서 공유를 하지 않기 때문
컴파일러의 기능을 최대한 활용하고 최적의 성능을 보장하기 위해 이 가정들을 이해하고 준수해야함
컴파일러가 처리하는 코드가 유효하며, 시맨틱 자바스크립트 원칙을 따른다고 가정
즉, 유효한 자바스크립트 문법을 사용하는지
안정성을 보장하기 위해, 컴파일러는 코드를 처리하기 전에 해당 코드가 널러블값과 옵셔널 값에 대한 안전 확인을 포함한다고 가정함
TS 설정에서 strictNullChecks 컴파일러 옵션을 활성화해 널러블 및 옵셔널 값을 안전하게 처리함을 보장할 수 있음
혹은 옵셔널 체이닝을 사용하여 조건 확인 수행
컴포넌트와 훅이 리액트 안에서 의도된 디자인 패턴과 일관되게 사용되었음을 보장하는것들이 포함됨
컴포넌트와 훅은 순수해야함 → 같은 입력이 들어오면 같은 결과를 반환해야함
컴포넌트는 멱등성을 가져야함 → 같은 입력으로 몇번을 실행해도 결과가 변하지 않아야함
props와 상태는 불변하게 다뤄져야함
훅은 '최상위 레벨', 및 리엑트 함수형 컴포넌트에서만 호출되어야함
...등등
컴포넌트와 훅들이 예측대로, 유지보수 가능하게 작동하는 것을 보장하는데 매우 중요
그리고 컴파일러가 효과적으로 최적화를 수행하는데 필수적
컴파일러는 이 규칙을 위반한 코드를 만나면 코드가 컴파일되도록 강제하는 시도를 하지 않음
안전하게 건너뛰고 나머지 코드를 계속 컴파일함
메타에선 프로덕션에 사용중이지만, 아직 공식적으로는 실험 단계
아직은 폭넓게 도입될 만큼 안정적이지 않다는것
서버 컴포넌트를 통해 서버 사이드 렌더링을 리액트 아키텍처에 매끄럽게 통합 가능
서버 사이드 렌더링 흐름은 간단히 페이지 진입 후 서버에서 HTML를 반환(렌더링) 후 클라이언트가 API 요청을 다시 서버로 보내 데이터를 가져와야 한다 (데이터 가져오기)
즉, 렌더링과 데이터 가져오기를 별도로 처리하는게 불-편
서버 사이드 데이터 가져오기를 직접적으로 컴포넌트 렌더링과 통합한 리액트 표준이 필요해짐 → 서버 컴포넌트
서버의 첫 응답에 데이터를 가져온다면 보다 효율적이고 프로세스를 간소화시켜 요청을 여러번 보낼 필요가 줄어들게됨
이전 next.js는 getServerSideProps라는 함수를 사용해 해결했음
리액트 서버 컴포넌트는 강력한 이익을 제공하며 점점 확산될것이지만, 리액트 생태계에 추가된 또 하나의 도구일 뿐, 기존 패턴들을 반드시 대체해야하는 것은 아님
개발자들은 프로젝트 요구사항에 맞는 최적의 접근 방법을 찾을 것
리액트의 새로운 기능
상태를 갖지 않는 컴포넌트
서버에서 실행됨
특정 계산과 데이터 가져오기 부담을 클라이언트에서 서버로 옮길 수 있음 (서버의 컴퓨팅 파워가 더 높으니 개이득)
클라이언트로 전달되는 코드양을 줄이고, 로딩 시간을 줄임 → 앱 사용성 개선
서버에서 배타적으로 실행되기에 전통적인 클라이언트 컴포넌트와 동작에 차이가 있음
서버에서 실행되므로 전통적인 리엑트 훅 사용 못함
서버 컴포넌트에서 상호작용을 도입하려면 상호작용을 다루는 클라이언트 컴포넌트를 활용해야함
즉, 서버 컴포넌트에서 상호작용 가능한 클라이언트 컴포넌트를 자식으로 사용
반대로 클라이언트 컴포넌트에서 자식으로 서버 컴포넌트를 사용할 수 없음
서버 컴포넌트는 서버에서만 실행되므로, 클라이언트 컴포넌트에서 직접 가져오면 클라이언트에서 실행할 방법이 없음
서버 컴포넌트는 비동기로 작동할 수 있음
await
키워드를 사용해 데이터를 꺼낼 때까지 대기함으로써 데이터를 완전히 로딩한 뒤 컴포넌트를 렌더링 가능
await
을 사용하지 않는 건은 데이터를 기다리지 않고 렌더링 프로세스를 진행시킴
대신 Suspense 컴포넌트에 의해 비동기로 가져오고 관리됨
서버에서 처리가 시작되지만 기다려지지 않으므로, 클라이언트에 비동기로 전달될 수 있음
use()
함수를 사용하면 컴포넌트는 서버 컴포넌트에서 전달된 프로미스를 구독하게됨
결과적으로 클라이언트 컴포넌트는 서버에서 요청된 비동기 데이터를 받게 되는 순간 즉시 렌더링
페이지 나머지 부분을 블로킹하지 않음
점진적 향상 원칙을 내포함, 기본 컨텐츠 기능은 한 번에 제공하고, 추가적인 기능들은 점진적으로 제공
클라이언트 컴포넌트가 서버 사이드 함수를 직접 호출하게 할 수 있음
2024년 9월까지는 모든 서버 함수를 "서버 액션"이라고 불렀습니다. 서버 함수가 액션 프로퍼티에 전달되거나 액션 내부에서 호출되면 서버 액션이지만 모든 서버 함수가 서버 액션인 것은 아닙니다. 이 문서의 명칭은 서버 함수가 여러 용도로 사용될 수 있다는 점을 반영하여 업데이트되었습니다.
이를 활용해서 때때로 서버 사이드 처리와 클라이언트 사이드의 동적 응답성의 장점을 조합할 수 있음
이 프로세스는 전체 페이지 재로딩을 요구하지 않음
클라이언트 사이드 상호작용의 실시간 응답성과 데이터 무결성 및 서버 사이드 동작의 처리 능력을 결합한 매끄러운 사용자 경험을 제공하게됨
서버 액션은 서버 컴포넌트 안에서 "use server" 지시자를 사용해 정의함
서버 컴포넌트에서 정의한 서버 액션을 props로 전달되어 클라이언트 컴포넌트에서 사용할 수 있음
클라이언트 컴포넌트 또한 "use server" 지시자를 선언한 파일에서 직접 서버 액션을 임포트 가능
서버 컴포넌트를 사용하면 서버 사이드 렌더링과 클라이언트 사이드 렌더링을 조합해 성능과 사용자 경험을 최적화 가능
RSC는 복잡한 계산과 데이터 가져오기를 서버로 넘겨서 클라이언트에 전달할 코드 양을 줄임
빠른 초기 로딩 시간과 성능 개선
서버 사이드 렌더링은 컨텐츠가 이미 검색 엔진에서 읽을 수 있는 상태임을 보장하므로 SEO를 향상시킴
RSC는 데이터 가져오기를 컴포넌트 렌더링 프로세스에 직접 통합하므로, 클라이언트는 별도의 API 호출을 할 필요가 없음
이 간소화된 접근법은 클라이언트 사이드의 상태와 데이터 동기화를 관리하는 복잡성을 줄임
리액트 컴파일러는 을 이해하며, 고급 정적 분석을 활용하여 컴포넌트와 리액트 앱의 훅 사이에 메모제이션을 지능적으로 적용함
리엑트 문서에는 이를 이라 부름
에서는 여러 다른 컴포넌트들이 하나의 값비싼 함수를 사용할것으로 예상된다면, 해당 함수 자체에 대한 메모이제이션을 구현하라고 안내함
리액트 컴파일러는 앱을 자동으로 최적화하는 한편, 처리 대상 코드에 대한 몇가지 에 의존함