React 17 에 추가된 새로운 것들(React 17- What’s new in the future?)
(https://www.zeolearn.com/magazine/react-17-whats-new-in-the-future 의 번역본입니다)
시작하며
NPM 에 React 16.3 alpha 버전이 새로운 Dev tool 들, Strict Mode, 바뀐 Context API 와 같은 자잘한 변경사항들을 발표한지 그리 오래 지나지나지 않았습니다. 하지만 지금은 굉장히 유용한 변경사항들을 가져왔으니 걱정하지 마세요.당신은 분명 기본 상태관리 이슈들을 핸들링할때 이것들을 사용하보고 싶으실 겁니다.
지난 JSConf 2018 에서 Redux 창시자이자 React 의 핵심 팀원인 Dan Abramov 가 문제제기한 React 16.3 의 기능들에 대하여 우리가 만족하지 못했던것은 당연했습니다(https://www.youtube.com/watch?v=CWXkcAe_mJA).
React 팀은 이번 React 17에서 다음 이슈들에 대해 정말 잘 처리 해주었습니다.
- 처리성능이 좋지 않은 장치에서의 응용 프로그램 상태관리
- 네트워크 수신 품질이 앱의 상태에 어떤 영향을 미치고 그 영향이 사용자 경험에 어떻게 작용하는지
React 17 의 미래를 살펴봅시다
Time Slicing
이런 이슈들을 해결하여 비동기 렌더링을보다 쉽고 안전하게 사용하기 위해 Time Slicing 개념이 만들어졌습니다.
JSConf 2018에서 Dan의 기조 연설 중 하나가 있습니다:
미래의 애플리케이션들은 점차 많은 사용자 인터페이스를 탑재하게 될 것입니다. 이 때 낮은 성능을 가진 기기에서 사용자가 앱을 탐색하는 동안 렌더링이 지연된다면 사용자에게 절대 잊을 수 없는 부정적인 경험이 될 것입니다.
Time Slicing 은 유휴 콜백 중에 자식 구성 요소에 대한 업데이트 계산을 여러 청크로 분할하여 여러 프레임에 걸쳐 렌더링 할 수 있습니다.
우선 순위가 낮은 UI 업데이트를 렌더링하기 전에 우선 순위가 높은 업데이트를 기다리는 대신 React는 우선 순위가 높은 업데이트가 중단되지 않은 상태에서 낮은 우선 순위의 업데이트 작업을 계속할 수 있도록 순서를 조정합니다.
Time Slicing은 개발자가 최소한의 신경을 써서 모든 CPU 할당 및 스케줄링 작업을 처리 할 수 있으므로 멋진 내부 처리(Under the hood - http://englishsamsam.tistory.com/110 | 역주)기능입니다.
Suspense
앱의 UI에 서로 다른 데이터 종속성을 가진 여러 component가 포함 된 상위 component가 있다고 가정 해 보겠습니다. 기본적으로 이것은 다른 비동기 요청을 트리거하는 비동기 요청 트리입니다. Redux 의 경우 부모 component에서 자식 component의 상태 요청을 해결함으로써 이 문제를 해결합니다. 하지만 React Suspense 는 이것을 다른 방법으로 해결하였습니다.
Suspense 를 사용하면 React가 비동기 데이터를로드하는 동안 상태 업데이트를 일시 중지 할 수 있습니다. Suspense 는 동시에 여러 상태를 관리할 수 있습니다.
네트워크 수신 상태가 좋지 않은 경우 앱이 로딩되는 동안 로딩 완료된 특정 부분만 표시하는 대신 다른 부분은 로딩 스피너를 표시하고 모든 요청이 처리된 경우에만 앱의 모든 부분을 렌더링합니다.
여기에 Dan 이 Suspense 의 핵심 기능에 대해 다음과 같이 tweet 하였습니다.
Suspense 가 작동하는 방식을 설명하는 과정에서 Dan은 기본적으로 createFetcher API를 사용했습니다.
이 API는 기본적으로 React가 렌더링 메서드 내에서 데이터 로드 요청을 일시 중단 할 수있게하는 캐시 시스템입니다. React 팀의 핵심 멤버 인 Andrew Clark도 createFetcher에 대해 트위터에서 설명했습니다.
또한 그의 트윗에서는 React의 또 다른 핵심 팀 멤버 인 Jamie Kyle이 다음과 같이 createFetcher 를 간단한 코드로 풀어 썼습니다.
function createFetcher(method) {
let resolved = new Map();
return {
read(key) => {
if (!resolved.has(key)) {
throw method(...args).then(val => resolved.set(key, val));
}
return resolved.get(key);
}
};
}
createFetcher - 이 글을 쓰는 시점에서는 매우 불안정한 API이므로 언제든지 변경 될 수 있습니다. 따라서 실제 응용 프로그램에서는 사용해서는 안됩니다. 당신은 Github에서 이것의 개발과정과 진행 상태에 대하여 구독할 수 있습니다.
Suspense 가 어떻게 작동하는지를 보여주기 위해 JSConf 2018 에서의 Dan’s IO demo 를 첨부합니다.
import { createFetcher, Placeholder, Loading } from '../future';
위 이미지에서 createFetcher API 에는 .read 메서드가 있으며 이는 캐시를 가져옵니다. 또한 이곳은 promise 을 반환하는 fetchMovieDetails 함수를 전달할 곳입니다.
MovieDetails 에서는 캐시에서 값을 읽어옵니다. 값이 이미 캐시되어있는 경우에도 캐시가 promise 를 제공하여 렌더링은 통상과 같이 계속됩니다.
promise 가 resolve 되면, React life cycle 은 중단 된 곳에서 다시 시작됩니다. 그런 다음 캐시는 새로운 컨텍스트 API를 사용하여 React 트리 전체에 공유됩니다.
일반적으로 component 는 context 에서 캐시됩니다. 이는 테스트하는 동안 임의의 캐시를 사용하여 네트워크 요청을 조작하는 것이 가능하다는 것을 의미합니다.
createFetcher는 simple-cache-provider를 사용하여 render 메서드 내에서 네트워크 요청을 일시 중단할 수 있으므로 모든 데이터가 반환되기 전에 렌더링을 시작할 수 있습니다. simple-cache-provider는 React가 필요로하는 component를 로딩하기 전에 요청을 초기화 시키는 데 사용할 수있는 .preload 메서드를 가지고 있습니다. 예를 들어, cinema app 에서 MovieReviews를 Movie로 전환하지만 MovieDetails 에만 일부 데이터가 필요합니다. Fetcher 와 함께라면 MovieDetails 의 데이터를 가져 오는 동안 React는 여전히 Movie를 렌더링 할 수 있습니다.
Suspense 를 사용한다면 앱은 완전히 동시에 상호 작용하면서 데이터를 가져올 수 있습니다. 덕분에 사용자가 주위 UI 를 클릭하고 다른 동작을하는 동안에도 지연이 발생할 가능성이 최소화됩니다. 위 사진에서 Placeholder component를 사용하여 비동기 요청을 기다리는 동안 MovieReviews 가 로드되는 데 1 초 이상 걸리는 경우 React가 로딩 스피너를 표시합니다.
위 사진에서 볼 수 있듯이 Loading component를 사용하면 데이터가 준비 될 때까지 모든 상태 업데이트를 일시 중단 한 다음 비동기 로드를 모든 component 트리에 추가 할 수 있습니다. 어떤것을 보여줄지 결정할 수있는 isLoading 이라는 property 를 렌더링하여 이를 수행합니다.
createFetcher와 마찬가지로 Loading도 simple-cache-provider의 일부이며 불안정합니다. 실제 응용 프로그램에서는 아직 사용하지 마십시오.
Deprecation of certain Component Lifecycle Methods
React 팀의 최근 블로그 게시물에서 component life cycle 메서드의 미래에 대해 논의했습니다. 물론 React 팀이 비동기 렌더링을 위해 특정 component life cycle 메서드를 변경할 것이라고 기대하지는 않았습니다. React의 원래 life cycle 모델은 비동기 렌더링을위한 것이 아니고 비동기 렌더링을 위한 사용이 늘어남에 따라 이러한 life cycle 메서드 중 일부는 안전하지 않은 경우가 생기곤 했습니다.
곧 deprecate 될 life cycle 메서드는 다음과 같습니다.
componentWillMount
componentWillUpdate
componentWillRecieveProps
세 가지 메서드 모두가 여전히 자주 사용되고 있습니다. deprecate 는 단계적으로 진행될 것입니다. 그들은 React 16.3에서 안전하지 않은 메서드로 분류 될 것입니다. 그리고 나서 그들은 특정 릴리즈 이후에 deprecated 경고를 추가 할 것이고, 마지막으로 React 17에서 사용되지 않을 것입니다.
deprecated 가 이 메서드들이 완전히 사라졌음을 의미할까요? 아닙니다. 사실, React 17 에서는 이 세가지 메서드의 이름에 안전하지 않다고 명시될 것이고 life cycle 에는 새로운 두가지 메서드가 추가될 것입니다.
UNSAFE_componentWillMount
UNSAFE_componentWillUpdate
UNSAFE_componentWillRecieveProps
getDerivedStateFromProps
getSnapshotBeforeUpdate
componentWillMount, componentWillUpdate 및 componentWillReceiveProps의 prefix는 UNSAFE입니다. 이것은 전혀 사용하지 않아야 하거나 사용해야하는 경우 주의해서 사용해야 함을 의미합니다. 예를 들어 비동기 렌더링과 함께 componentWillMount를 사용하면 구성 요소 트리를 여러 번 렌더링 하게 될 수 있습니다. 이 이유만으로도 안전하지 않은 것으로 간주됩니다.
Dan은 앞으로 componentDidMount를 사용하여 server-side-rendering 을 어떻게 구현해야 할지를 트윗에서 설명합니다.
새로 생성 된 두 가지 메서드 모두에 대해 설명하기 위해 계속 진행해 보겠습니다: getDerivedStateFromProps, getSnapshotBeforeUpdate
getDerivedStateFromProps
이 메서드는 static 요소이며 componentWillReceiveProps와 componentDidUpdate를 함께 사용해야 했던 작업을 처리할 수 있습니다. 이것은 componentWillReceiveProps의 안전한 대체품으로 만들어졌습니다. component가 작성된 후 호출되며 새 component를 받으면 호출됩니다.
static getDerivedStateFromProps(nextProps, prevState) {
// ...
}
getDerivedStateFromProps는 property 변경에 대한 응답으로 상태를 업데이트 할 객체를 반환합니다. 상태 변경을 원하지 않는다면 null을 반환합니다. property 가 변경되지 않아도 React가 이 메소드를 직접 호출 할 수 있습니다.
getSnapshotBeforeUpdate
이 메소드는 DOM이 업데이트되기 바로 전에 호출되며, componentWillUpdate와 componentDidUpdate를 함께 사용해야 했던 작업을 처리할 수 있습니다. DOM 업데이트 후 getSnapshotBeforeUpdate에서 반환 된 값은 componentDidUpdate로 전달됩니다.
getSnapshotBeforeUpdate(prevProps, prevState) {
// ...
}
getSnapshotBeforeUpdate의 유용한 사용 예로는 비동기 렌더링 중에 앱의 창 크기를 조정하는 것이 있을 것입니다.
정리하며
Time Slice는 아무런 추가 고려 사항없이 우리의 어려운 CPU 스케줄링 작업을 모두 처리할 수 있게 해줍니다.
Suspense를 사용하면 이전 뷰를 그대로 유지하면서 전체 component 트리가 준비 될 때까지 몇 초 동안 컨텐츠의 렌더링을 지연시킴으로써 여러 상태를 관리 할 수 있습니다.
다음은 JSConf 2018에서 Dan이 지적한 것들의 요점입니다.
JSConf 2018 의 Dan의 전체 프레젠테이션을 보시고 React 17의 새로운 기능들에 대한 자세한 내용을 더 보실 것을 권합니다.
'it > programming' 카테고리의 다른 글
Pynecone.io, 매력적이지만 아직은 아쉬운 (4) | 2023.03.07 |
---|---|
Digging Github, 우리가 어쩌면 몰랐던 GitHub의 여러 기능들 (0) | 2017.01.22 |
imgur api 를 이용하여 서버 없이 이미지 업로드 하기 (1) | 2016.12.01 |