sbyeol3/articles

[번역] React의 궁극적 원리 - 소프트웨어 디자인, 아키텍쳐 & 좋은 예시 2

Opened this issue · 0 comments

원문 : 2021.01.18에 작성된 Tao of React - Software Design, Architecture & Best Practices

성능 (Performance)

너무 빨리 최적화하려고 하지 마라

어떤 최적화를 하기 전에 최적화에 대한 이유가 있는지 확인하세요. 여러분의 어플리케이션에 영향을 주지 않음에도 맹목적으로 좋은 사례를 따라하는 것은 노력을 허비할 뿐입니다. 중요한 걸 아는 것도 필요합니다만, 성능 이전에 가독성 있고 유지보수 가능한 컴포넌트를 만드는 것을 더 우선으로 해야 합니다. 잘 쓰여진 코드가 개선하기 쉽습니다.

여러분의 앱에 성능문제가 있을 때 문제의 원인을 측정하고 무엇인지 확인하세요. 번들 사이즈가 거대하다면 리렌더링 횟수를 줄여도 소용이 없습니다. 성능 문제가 있다는 것을 일단 알면 문제의 영향 순서에 따라 수정해야 합니다.

번들 사이즈를 확인하라

브라우저에 전달되는 자바스크립트의 양은 어플리케이션 성능의 가장 주요한 요소입니다. 여러분의 앱이 엄청 빠르더라도 4MB의 JS 코드를 로드해야 한다면 아무도 여러분의 앱이 빠른 것을 알지 못할 겁니다. 하나의 번들을 전달하지 말고 여러분의 앱을 route 수준으로 쪼개도록 하세요. 가능한 최소한의 JS 코드를 전달하도록 해야 합니다.

백그라운드로 로드하거나 사용자가 다른 번들이 필요할 때 로드합니다. 어떤 버튼이 PDF를 다운로드하는 것을 트리거한다면, 버튼이 hover되었을 때 PDF 라이브러리를 다운로드하도록 지연시킬 수 있습니다.

Rerenders - 콜백, 배열, 객체

불필요한 리렌더링의 회수를 줄이는 것은 좋은 시도입니다. 다만, 불필요한 리렌더링은 여러분의 앱에 엄청난 영향을 미치는 경우가 거의 없다는 것을 유의하세요. 가장 흔한 조언은 props로 콜백 함수를 전달하는 것을 지양하는 것입니다. 각 새로운 함수가 생성될 때마다 리렌더링을 유발하기 때문입니다. 콜백함수로 인해 성능 문제를 겪은 적은 없었고, 사실 그것이 제가 접근하고자 하는 방식입니다.

여러분이 성능 문제를 겪고 있고 클로져가 원인이라면 클로져를 제거하세요. 그러나 코드의 가독성을 해치거나 더 장황하게 만들지는 마세요. 배열이나 객체를 아래로 전달하는 것은 비슷한 결입니다. 참조 체크에 실패하면 리렌더링을 유발하죠. 고정된 배열을 전달하고자 한다면, 컴포넌트 정의에 앞서 배열을 상수로 선언함으로써 동일한 인스턴스가 전달될 것입니다.

테스트 (Testing)

스냅샷 테스트에 의존하지 마라

React로 2016년부터 작업하면서 제 컴포넌트에서 스냅샷 테스트가 문제를 캐치한 적은 딱 한 번 있습니다. 인자 없이 new Date()를 호출하여 항상 현재 날짜로 기본 설정되었던 거죠. 게다가 스냅샷은 컴포넌트가 변경될 때마다 빌드 실패의 원인이 됩니다. 일반적인 워크플로우는 컴포넌트를 변경하고 스냅샷에 오류가 있는지 확인한 후 스냅샷을 업데이트하고 계속 진행합니다. 오해하지 마세요. 스냅샷 테스트는 좋은 새너티 체크지만 컴포넌트 수준의 테스트를 위한 대체품이 될 수는 없습니다. 저는 스냅샷을 생성하는 것조차를 지양합니다.

올바른 렌더링을 테스트하라

여러분의 테스트가 검증해야 하는 것은 컴포넌트가 예상대로 동작하는 것입니다. 컴포넌트가 기본값의 props와 전달되는 props로 올바르게 렌더되는지 확인해야 합니다. 주어진 인풋에 대해 함수가 올바르게 결과를 리턴하는지를 검증하세요. 스크린에서 필요한 모든 것들을 검증하세요.

상태와 이벤트를 검증하라

상태가 있는 컴포넌트는 이벤트의 응답에 따라 변경됩니다. 이벤트를 시뮬레이션하고 컴포넌트가 그에 적절히 반응하는지 확인하세요. 핸들러 함수가 호출되고 적절한 인자가 전달되는지 검증하세요. 또한 내부 상태가 잘 설정되는지 확인하세요.

테스트 엣지 케이스 (Test Edge Cases)

엣지 케이스를 테스트하라

기본적인 테스트를 다뤘다면, 엣지 케이스를 다루기 위해 몇 가지를 추가해야 합니다. 빈 배열을 전달했을 때 체킹없이 인덱스를 접근하지 않도록 해야 합니다. API 호출에서 에러를 발생시켜 컴포넌트가 해당 오류를 잘 처리하는지 확인합니다.

통합 테스트를 작성하라

통합 테스트는 전체 페이지나 큰 컴포넌트를 검증하는 것을 의미합니다. 추상화로서 잘 작동하는지 확인하는 것이죠. 이 테스트는 앱이 예상대로 잘 작동한다는 자신감을 줍니다. 컴포넌트 자체로도 잘 작동하고 유닛 테스트 단위로도 테스트를 통과할 수 있지만 통합되었을 때 문제가 있을 수 있습니다.

스타일링 (Styling)

CSS-in-JS를 사용하라

많은 사람들이 동의하지 않고 여러 논란을 야기할 의견입니다. 저는 자바스크립트에서 컴포넌트에 대한 모든 것들을 표현이 가능하기 때문에 Styled Components나 Emotion과 같은 라이브러리를 선호합니다. 관리할 파일이 하나 줄어들며 CSS 컨벤션에 대해 생각할 필요가 없습니다. 리액트에서 논리 단위는 컴포넌트이므로 관심사를 분리하는 관점에서도 컴포넌트와 관련된 모든 것들을 컴포넌트가 소유해야 합니다.

주의 : 스타일에 대한 잘못된 선택은 없습니다. SCSS, CSS 모듈, Tailwind와 같은 라이브러리 등. CSS-in-JS는 제가 추천하는 접근 방식일 뿐입니다.

Styled component를 함께 두어라.

CSS-in-JS 컴포넌트를 사용할 때 한 파일에 여러 개를 같이 두는 것이 일반적입니다. 같은 파일을 사용하는 일반 컴포넌트와 동일한 파일에 보관하는 것이 좋습니다. 그러나 너무 스타일 코드가 너무 길어지게 되면 분리해서 스타일을 사용하는 컴포넌트 근처에 두는 것이 좋습니다. Spectrum과 같은 오픈 소스 프로젝트에서 이러한 패턴을 볼 수 있습니다.

데이터 가져오기 (Data Fetching)

data fetching 라이브러리를 사용하라

리액트는 API에서 데이터를 가져오거나 업데이트하는 고집된 방법을 제공하지 않습니다. 각 팀은 API와 통실하는 비동기 함수들을 제공하는 자신들만의 서비스에 관련된 자체 구현을 만들어내죠. 이 방식을 선택하면 로딩 상태를 관리하고 http 에러들을 다루는 것들을 우리가 직접 해야 합니다. 이는 장황한 코드를 가지는 보일러플레이트를 필요로 합니다. 직접 구현하는 대신 React Query나 SWR과 같은 라이브러리를 사용하세요. hook이라는 관용적인 방식을 통해 서버와 통신하는 것을 컴포넌트 라이프사이클의 자연스러운 부분으로 만듭니다. 또한 캐싱 기능을 제공하고 로딩과 에러 상태를 관리합니다. 우리는 그 기능을 다루기만 하면 됩니다. 또한 데이터를 다루기 위해 상태 관리 라이브러리를 사용할 필요를 없애줍니다.