더 나은 Redux 아키텍처를위한 10 가지 팁

만다린 오리-말콤 카라 (CC-BY-2.0)

React를 사용하기 시작했을 때 Redux는 없었습니다. Flux 아키텍처와 약 12 ​​개의 경쟁 구현이있었습니다.

이제 React에는 데이터 관리 분야에서 Redux와 MobX라는 두 가지 확실한 승자가 있으며 후자는 Flux 구현도 아닙니다. Redux는 더 이상 React에 사용되는 것이 아닙니다. Angular 2를 포함한 다른 프레임 워크에 대한 Redux 아키텍처 구현을 찾을 수 있습니다 (예 : ngrx : store 참조).

참고 사항 : MobX는 멋지다. 간단한 UI를 위해 Redux를 선택했을 것이다. 즉, MobX가 제공하지 않는 Redux의 몇 가지 중요한 기능이 있으며 프로젝트에 적합한 것을 결정하기 전에 해당 기능이 무엇인지 이해하는 것이 중요합니다.
참고 사항 : Relay 및 Falcor는 상태 관리를위한 다른 흥미로운 솔루션이지만 Redux 및 MobX와 달리 각각 GraphQL 및 Falcor Server의 지원을 받아야하며 모든 Relay 상태는 일부 서버 지속 데이터에 해당합니다. AFAIK는 클라이언트 측의 일시적인 상태 관리에 대한 좋은 이야기를 제공하지 않습니다. 클라이언트 전용 상태와 서버 지속 상태를 구분하여 Relay 또는 Falcor를 Redux 또는 MobX와 혼합하여 일치시킴으로써 이점을 누릴 수 있습니다. 결론 : 현재 클라이언트에서 상태 관리를위한 확실한 단일 승자는 없습니다. 현재 작업에 적합한 도구를 사용하십시오.

Redux의 창시자 인 Dan Abramov는 다음과 같은 주제에 대해 훌륭한 코스를 두었습니다.

  • Redux 시작하기
  • 관용적 Redux로 애플리케이션 구축

둘 다 Redux 기초를 설명하는 훌륭한 단계별 자습서이지만 Redux를 최대한 활용하려면 더 높은 수준의 이해가 필요합니다.

다음은 더 나은 Redux 앱을 구축하는 데 도움이되는 팁입니다.

1. Redux의 이점 이해

Redux에는 몇 가지 중요한 목표를 명심해야합니다.

  1. 결정 론적 뷰 렌더
  2. 결정 론적 국가 복제

결정 성은 응용 프로그램 테스트 가능성과 버그 진단 및 수정에 중요합니다. 애플리케이션보기 및 상태가 결정적이지 않은 경우보기 및 상태가 항상 유효한지 여부를 알 수 없습니다. 비결정론 자체가 버그라고 말할 수도 있습니다.

그러나 어떤 것은 본질적으로 비 결정적입니다. 사용자 입력 타이밍 및 네트워크 I / O와 같은 것. 그렇다면 코드가 실제로 작동하는지 어떻게 알 수 있습니까? 쉬움 : 격리.

Redux의 주요 목적은 상태 관리를 뷰 렌더링 또는 네트워크 작업과 같은 I / O 부작용과 분리하는 것입니다. 부작용이 분리되면 코드가 훨씬 단순 해집니다. 네트워크 요청 및 DOM 업데이트와 관련이없는 비즈니스 로직을 이해하고 테스트하는 것이 훨씬 쉽습니다.

뷰 렌더가 네트워크 I / O 및 상태 업데이트와 격리되면 결정 론적 뷰 렌더를 얻을 수 있습니다. 즉, 동일한 상태에서 뷰는 항상 동일한 출력을 렌더링합니다. 비동기 뷰에서 무작위로 뷰의 비트를 지우거나 뷰가 렌더링 프로세스 중일 때 상태 비트를 제거함으로써 경쟁 조건과 같은 문제의 가능성을 제거합니다.

초보자는 뷰 생성에 대해 생각할 때“이 비트에는 사용자 모델이 필요하므로이를 가져 오기 위해 비동기 요청을 시작하고 약속이 해결되면 사용자 구성 요소의 이름으로 업데이트합니다. 저쪽에는 할 일 항목이 필요하므로 가져 와서 약속이 해결되면 반복해서 화면에 표시합니다.”

이 방법에는 몇 가지 주요 문제가 있습니다.

  1. 주어진 시점에 전체 뷰를 렌더링하는 데 필요한 모든 데이터가 없습니다. 실제로 구성 요소가 작업을 시작하기 전까지는 데이터를 가져 오기 시작하지 않습니다.
  2. 뷰 페치 순서에서 발생하는 순서를 미묘하게 변경하여 다른 페치 작업이 다른 시간에 발생할 수 있습니다. 렌더링 시퀀스를 진정으로 이해하려면 예측할 수없는 항목, 즉 각 비동기 요청의 지속 기간에 대한 지식이 있어야합니다. 팝 퀴즈 : 위 시나리오에서 사용자 구성 요소 또는 작업 항목을 먼저 렌더링하는 것은 무엇입니까? 답 : 경주입니다!
  3. 때때로 이벤트 리스너는 뷰 상태를 변경하여 다른 렌더링을 트리거하여 시퀀스를 더 복잡하게 만듭니다.

데이터를 뷰 상태로 저장하고 비동기 이벤트 리스너에게 뷰 상태를 변경하는 액세스 권한을 부여하는 데있어 주요 문제점은 다음과 같습니다.

“비결 정성 = 병렬 처리 + 공유 상태”
~ Martin Odersky (스칼라 디자이너)
데이터 가져 오기, 데이터 조작 및 뷰 렌더 문제를 밍 글링하는 것은 시간 여행 스파게티를위한 레시피입니다.

나는 B 영화 공상 과학 같은 방식으로 좀 멋지다는 것을 알고 있지만 시간 여행 스파게티는 최악의 시음 종류입니다!

플럭스 아키텍처는 엄격한 분리 및 순서를 적용하여 매번 이러한 규칙을 준수합니다.

  1. 먼저 알려진 고정 상태가됩니다.
  2. 그런 다음 뷰를 렌더링합니다. 이 렌더 루프의 상태는 다시 변경할 수 없습니다.
  3. 동일한 상태에서 뷰는 항상 같은 방식으로 렌더링됩니다.
  4. 이벤트 리스너는 사용자 입력 및 네트워크 요청 핸들러를 청취합니다. 그들이 얻을 때, 조치는 상점으로 발송됩니다.
  5. 작업이 전달되면 상태가 알려진 새로운 상태로 업데이트되고 시퀀스가 ​​반복됩니다. 디스패치 된 작업 만 상태를 만질 수 있습니다.

간단히 말해 플럭스 : UI를위한 단방향 데이터 흐름 아키텍처 :

플럭스 아키텍처

Flux 아키텍처를 사용하면보기는 사용자 입력을 청취하고이를 조치 오브젝트로 변환하여 상점으로 전달합니다. 상점은 애플리케이션 상태를 업데이트하고 다시 렌더링하도록보기에 알립니다. 물론 뷰가 유일한 입력 및 이벤트 소스는 아니지만 문제가되지 않습니다. 추가 이벤트 리스너는 뷰와 같이 액션 객체를 전달합니다.

중요하게 Flux의 상태 업데이트는 트랜잭션입니다. 단순히 상태에서 update 메소드를 호출하거나 값을 직접 조작하는 대신 조치 오브젝트가 상점으로 전달됩니다. 활동 오브젝트는 트랜잭션 레코드입니다. 은행 거래와 같은 것으로 생각할 수 있습니다. 은행에 입금하면 5 분 전의 잔액이 지워지지 않습니다. 대신, 새로운 잔액이 거래 내역에 추가됩니다. 작업 개체는 응용 프로그램 상태에 트랜잭션 기록을 추가합니다.

액션 객체는 다음과 같습니다 :

조치 오브젝트가 제공하는 것은 모든 상태 트랜잭션의 실행 로그를 유지하는 기능입니다. 이 로그를 사용하여 상태를 결정적인 방식으로 재현 할 수 있습니다.

동일한 초기 상태와 동일한 트랜잭션이 동일한 순서로 주어지면 항상 결과와 동일한 상태가됩니다.

이것은 중요한 의미를 갖습니다.

  1. 쉬운 테스트 가능성
  2. 간편한 실행 취소 / 다시 실행
  3. 시간 여행 디버깅
  4. 내구성 — 상태가 지워지더라도 모든 트랜잭션에 대한 기록이 있으면이를 재현 할 수 있습니다.

공간과 시간을 숙달하고 싶지 않은 사람은 누구입니까? 거래 상태는 시간 여행 초강대국을 제공합니다.

Redux 개발 도구 기록 슬라이더보기

2. 일부 앱은 Redux가 필요하지 않습니다

UI 워크 플로가 단순하면이 모든 것이 과도 할 수 있습니다. 틱택 토 게임을하는 경우 실행 취소 / 다시 실행이 필요합니까? 게임은 거의 1 분 이상 지속되지 않습니다. 사용자가 실수하면 게임을 재설정하고 다시 시작할 수 있습니다.

만약:

  • 사용자 워크 플로우는 간단합니다
  • 사용자는 공동 작업하지 않습니다
  • 서버 측 이벤트 (SSE) 또는 웹 소켓을 관리 할 필요가 없습니다.
  • 뷰당 단일 데이터 소스에서 데이터를 가져옵니다.

앱의 이벤트 시퀀스는 아마도 트랜잭션 상태의 이점이 추가 노력의 가치가 없을 정도로 충분히 단순 할 수 있습니다.

앱을 Fluxify하지 않아도됩니다. 이와 같은 앱에는 훨씬 간단한 솔루션이 있습니다. MobX를 확인하십시오.

그러나 앱의 복잡성이 증가함에 따라 뷰 상태 관리의 복잡성이 증가함에 따라 트랜잭션 상태의 가치도 높아지고 MobX는 즉시 트랜잭션 상태 관리를 제공하지 않습니다.

만약:

  • 사용자 워크 플로우는 복잡합니다
  • 앱에는 다양한 사용자 워크 플로가 있습니다 (일반 사용자와 관리자 모두 고려)
  • 사용자는 협업 할 수 있습니다
  • 웹 소켓 또는 SSE를 사용하고 있습니다.
  • 단일 뷰를 구축하기 위해 여러 엔드 포인트에서 데이터를로드하고 있습니다.

트랜잭션 상태 모델을 통해 충분한 가치를 얻을 수 있습니다. Redux가 적합 할 수 있습니다.

웹 소켓과 SSE는 이것과 어떤 관련이 있습니까? 비동기 I / O 소스를 더 많이 추가할수록 불확실한 상태 관리를 통해 앱에서 발생하는 상황을 이해하기가 더 어려워집니다. 결정적 상태와 상태 트랜잭션 기록은 이와 같은 앱을 근본적으로 단순화합니다.

제 생각에는 대부분의 대형 SaaS 제품에는 최소한 몇 가지 복잡한 UI 워크 플로가 포함되므로 트랜잭션 상태 관리를 사용해야합니다. 대부분의 작은 유틸리티 앱과 간단한 프로토 타입은 사용하지 않아야합니다. 작업에 적합한 도구를 사용하십시오.

3. 감속기 이해

Redux = 플럭스 + 기능 프로그래밍

플럭스는 액션 객체로 단방향 데이터 흐름과 트랜잭션 상태를 규정하지만 액션 객체를 처리하는 방법에 대해서는 언급하지 않습니다. 그것이 Redux가 들어오는 곳입니다.

Redux 상태 관리의 기본 구성 요소는 감속기 기능입니다. 감속기 기능이란 무엇입니까?

함수형 프로그래밍에서 공통 유틸리티`reduce ()`또는`fold ()`는 단일 출력 값을 누적하기 위해 값 목록의 각 값에 감속기 함수를 적용하는 데 사용됩니다. 다음은`Array.prototype.reduce ()`를 사용하여 JavaScript 배열에 적용된 합산 감속기의 예입니다.

Redux는 어레이에서 작동하는 대신 액션 객체 스트림에 리듀서를 적용합니다. 액션 객체는 다음과 같습니다.

위의 합산 감속기를 Redux 스타일 감속기로 바꾸어 봅시다.

이제 몇 가지 테스트 작업에 적용 할 수 있습니다.

4. 감속기는 순수한 기능이어야 함

결정적 상태 재현을 달성하려면 감속기가 순수한 기능이어야합니다. 예외 없음. 순수한 기능 :

  1. 동일한 입력이 주어지면 항상 동일한 출력을 반환합니다.
  2. 부작용이 없습니다.

중요하게는 JavaScript에서 기본이 아닌 모든 객체는 함수로 참조로 전달됩니다. 즉, 객체를 전달한 다음 해당 객체의 속성을 직접 변경하면 객체는 함수 외부에서도 변경됩니다. 그것은 부작용입니다. 전달한 객체의 전체 기록을 모르면 함수 호출의 전체 의미를 알 수 없습니다.

리듀서는 대신 새 객체를 반환해야합니다. 예를 들어`Object.assign ({}, state, {thingToChange})`로이를 수행 할 수 있습니다.

배열 매개 변수도 참조입니다. `.push ()`는 변경 작업이므로`.push ()`새 항목을 감속기의 배열에 넣을 수 없습니다. 마찬가지로`.pop ()`,`.shift ()`,`.unshift ()`,`.reverse ()`,`.splice ()`및 기타 뮤 테이터 메소드도 마찬가지입니다.

배열을 안전하게 사용하려면 상태에서 수행하는 작업을 안전한 접근 자 메서드로 제한해야합니다. `.push ()`대신`.concat ()`을 사용하십시오.

이 채팅 감속기의`ADD_CHAT` 사례를 살펴보십시오.

보다시피,`Object.assign ()`으로 새로운 객체가 생성되고`.push ()`대신`.concat ()`로 배열에 추가됩니다.

개인적으로 실수로 상태를 변경하는 것에 대해 걱정하고 싶지 않으므로 최근 Redux에서 불변 데이터 API를 사용하여 실험하고 있습니다. 내 상태가 변경 불가능한 객체 인 경우 객체가 실수로 변형되지 않았 음을 알기 위해 코드를 볼 필요조차 없습니다. 팀에서 일하면서 우연한 상태 돌연변이로 인한 버그를 발견 한 후이 결론에 도달했습니다.

이것보다 순수한 기능에 더 많은 것이 있습니다. 프로덕션 앱에 Redux를 사용하려면 순수한 함수가 무엇인지, 시간, 로깅 및 난수 처리와 같이 염두에 두어야 할 사항을 잘 파악해야합니다. 이에 대한 자세한 내용은“JavaScript 인터뷰 마스터 : 순수한 기능이란 무엇입니까?”를 참조하십시오.

5. 기억하십시오 : 감속기는 진실의 단일 근원이어야합니다

앱의 모든 상태에는 단일 진실 소스가 있어야합니다. 즉, 상태가 단일 장소에 저장되어 있고, 필요한 다른 곳에서는 단일 진리 소스를 참조하여 상태에 액세스해야합니다.

다른 것들에 대해 다른 진실의 근원을 갖는 것이 좋습니다. 예를 들어, URL은 사용자 요청 경로 및 URL 매개 변수에 대한 단일 진실 소스가 될 수 있습니다. 앱에 API URL의 단일 소스 인 구성 서비스가있을 수 있습니다. 괜찮아. 하나…

Redux 저장소에 상태를 저장하면 Redux를 통해 해당 상태에 액세스해야합니다. 이 원칙을 준수하지 않으면 Flux와 Redux가 해결하기 위해 오래된 데이터 또는 공유 상태 돌연변이 버그가 발생할 수 있습니다.

다시 말해, 단일 진실 원칙의 원천이 없다면 잠재적으로 다음과 같은 것을 잃을 수 있습니다.

  • 결정 론적 뷰 렌더
  • 결정적 상태 재현
  • 간편한 실행 취소 / 다시 실행
  • 시간 여행 디버깅
  • 쉬운 테스트 가능성

Redux 또는 상태를 Redux하지 마십시오. 절반 만하면 Redux의 모든 이점을 취소 할 수 있습니다.

6. 액션 타입에 상수 사용

작업 내역을 볼 때 해당 작업을 사용하는 감속기에서 작업을 쉽게 추적 할 수 있는지 확인하고 싶습니다. 모든 작업에`CHANGE_MESSAGE`와 같이 짧고 일반적인 이름이 있으면 앱에서 무슨 일이 일어나고 있는지 이해하기가 더 어려워집니다. 그러나 액션 유형에`CHAT :: CHANGE_MESSAGE`와 같이보다 구체적인 이름이있는 경우 진행 상황이 훨씬 분명합니다.

또한 오타를 만들고 정의되지 않은 동작 상수를 전달하면 앱에서 오류를 경고하여 실수를 경고합니다. 조치 유형 문자열로 오타를 작성하면 조치가 자동으로 실패합니다.

감속기의 모든 작업 유형을 파일 상단의 한 곳에 모아두면 다음과 같은 도움이 될 수 있습니다.

  • 일관된 이름 유지
  • 리듀서 API를 빠르게 이해
  • 풀 요청에서 변경된 사항보기

7. 액션 생성자를 사용하여 디스패치 호출자와 액션 로직 분리

사람들에게 ID를 생성 할 수 없거나 감속기에서 현재 시간을 잡을 수 없다고 말하면 재미있는 표정이됩니다. 의심스럽게 화면을 응시하고 있다면 안심하십시오. 혼자가 아닙니다.

그렇다면 불순한 논리를 처리하기에 좋은 곳은 어디에서든지 반복적으로 조치를 취하지 않아도 되는가? 액션 크리에이터.

액션 제작자는 다음과 같은 다른 이점도 있습니다.

  • 액션 유형 상수를 리듀서 파일에 캡슐화하여 다른 곳으로 가져올 필요가 없습니다.
  • 조치를 전달하기 전에 입력을 계산하십시오.
  • 상용구 줄이기

액션 제작자를 사용하여`ADD_CHAT` 액션 객체를 생성 해 봅시다 :

위에서 볼 수 있듯이 cuid를 사용하여 각 채팅 메시지에 대해 임의의 ID를 생성하고`Date.now ()`를 사용하여 타임 스탬프를 생성합니다. 둘 다 리듀서에서 실행하기에 안전하지 않은 불완전한 작업이지만 액션 제작자에서 실행해도 괜찮습니다.

액션 크리에이터로 보일러 플레이트 줄이기

일부 사람들은 액션 제작자를 사용하면 프로젝트에 상용구가 추가된다고 생각합니다. 반대로, 감속기의 보일러 플레이트를 크게 줄이는 데 어떻게 사용하는지 보려고합니다.

팁 : 상수, 감속기 및 액션 생성기를 모두 같은 파일에 저장하면 별도의 위치에서 가져올 때 상용구를 줄일 수 있습니다.

채팅 사용자가 사용자 이름 및 가용성 상태를 사용자 정의 할 수있는 기능을 추가하려고한다고 가정하십시오. 다음과 같이 몇 가지 액션 타입 핸들러를 리듀서에 추가 할 수 있습니다 :

더 큰 감속기의 경우 이것은 많은 상용구로 자랄 수 있습니다. 내가 만든 많은 감속기는 중복 코드가 많기 때문에 그보다 훨씬 복잡해질 수 있습니다. 간단한 속성 변경 작업을 모두 축소 할 수 있다면 어떨까요?

밝혀졌습니다. 쉽습니다.

여분의 간격과 주석이 있어도이 버전은 더 짧으며 두 가지 경우에 불과합니다. 저축은 실제로 더해질 수 있습니다.

전환하지 않습니까… 대소 문자가 위험한가요? 넘어지는 걸 봅니다!

당신은 어쩌면 우연히 넘어지지 않고 사건 목록이 부풀어 올 수 있기 때문에 스위치 진술을 피해야 할 곳을 읽었을 것입니다. 실수로 넘어지는 버그를 잡기가 어렵 기 때문에 의도적으로 넘어지지 않아야한다는 말을 들었을 것입니다. 이것이 좋은 조언이지만 위에서 언급 한 위험에 대해 신중하게 생각해 봅시다.

  • 감속기는 구성이 가능하므로 대소 팽창은 문제가되지 않습니다. 케이스 목록이 너무 커지면 조각을 분리하여 별도의 감속기로 옮깁니다.
  • 모든 케이스 본체가 반환되므로 실수로 넘어지지 않아야합니다. 그룹화 된 추락 사건 중 어느 것도 캐치를 수행하는 신체 이외의 신체를 가져서는 안됩니다.

Redux는`switch..case`를 잘 사용합니다. 공식적으로이 문제에 대한 조언을 변경하고 있습니다. 위의 간단한 규칙을 준수하는 한 (스위치를 작고 집중 한 상태로 유지하고 자신의 신체가있는 모든 경우에서 복귀)`스위치 '문은 좋습니다.

이 버전에는 다른 페이로드가 필요하다는 것을 알 수 있습니다. 이곳은 액션 제작자가 들어오는 곳입니다.

보시다시피, 이러한 액션 제작자는 인수와 상태 형태를 변환합니다. 하지만 이것이 그들이하는 전부는 아닙니다 ...

8. 서명 문서에 ES6 매개 변수 기본값 사용

Sublime Text 및 Atom과 같은 인기있는 편집기에서 사용할 수있는 편집기 플러그인으로 Tern.js를 사용하는 경우 ES6 기본 할당을 읽고 액션 작성자의 필수 인터페이스를 유추하므로 호출 할 때, 당신은 지능과 자동 완성을 얻을 수 있습니다. 필요한 페이로드 유형을 기억하거나 잊어 버렸을 때 소스 코드를 확인할 필요가 없기 때문에 개발자의인지 부하가 ​​줄어 듭니다.

Tern, TypeScript 또는 Flow와 같은 형식 유추 플러그인을 사용하지 않는 경우 사용해야합니다.

참고 : 유형 주석과 달리 함수 서명에 표시되는 기본 할당에서 제공하는 추론에 의존하는 것을 선호합니다.

  1. Flow 또는 TypeScript를 사용하여 작동시키지 않아도됩니다. 대신 표준 JavaScript를 사용하십시오.
  2. TypeScript 또는 Flow를 사용하는 경우 TypeScript와 Flow 모두 기본 할당에서 유형을 유추하므로 주석은 기본 할당으로 중복됩니다.
  3. 구문 노이즈가 적을 때 훨씬 더 읽기 쉽습니다.
  4. 기본 설정을 얻습니다. 즉, 유형 오류에 대한 CI 빌드를 중지하지 않더라도 (놀랄 것입니다. 많은 프로젝트는 그렇지 않습니다) 우발적 인 '정의되지 않은'매개 변수가 없습니다. 암호.

9. 계산 된 상태 및 디커플링에 선택기 사용

채팅 앱 기록에서 가장 복잡한 채팅 앱을 구축한다고 가정 해보십시오. 5 만 줄의 코드를 작성했으며, 제품 팀은 새로운 기능 요구 사항을 제시하여 해당주의 데이터 구조를 변경해야합니다.

당황 할 필요가 없습니다. 선택기의 상태 모양에서 나머지 앱을 분리 할 수있을만큼 똑똑했습니다. 총알 : 피했다.

필자가 작성한 거의 모든 리듀서에 대해 뷰를 구성하는 데 필요한 모든 변수를 내보내는 선택기를 만듭니다. 간단한 채팅 감속기의 모습을 살펴 보겠습니다.

내보내기 const getViewState = state => state;

그래, 알아 너무 간단해서 요점도 없습니다. 내가 지금 미쳤다고 생각할 수도 있지만 이전에 피한 총알을 기억하십니까? 이 세션에서 채팅 한 모든 사용자의 전체 목록과 같이 계산 된 상태를 추가하려면 어떻게해야합니까? 이것을 'recentlyActiveUsers'라고하겠습니다.

이 정보는 이미 현재 상태로 저장되어 있지만 파악하기 쉬운 방식은 아닙니다. 계속해서`getViewState ()`에서 봅시다 :

계산 된 모든 상태를 선택기에 넣으면 다음을 수행 할 수 있습니다.

  1. 감속기 및 구성 요소의 복잡성 감소
  2. 나머지 앱을 상태 모양에서 분리
  3. 감속기 내에서도 단일 진실 원칙 소스를 준수하십시오.

10. TDD : 쓰기 테스트를 먼저 사용하십시오.

많은 연구에서 테스트 후 방법론과 테스트 후 방법론을 비교했으며 전혀 테스트하지 않았습니다. 결과는 명확하고 극적입니다. 대부분의 연구에 따르면 기능을 구현하기 전에 테스트를 작성한 결과 배송 버그가 40 ~ 80 % 감소합니다.

TDD는 배송 버그 밀도를 효과적으로 절반으로 줄일 수 있으며 해당 주장을 뒷받침 할 증거가 많이 있습니다.

이 기사의 예제를 작성하는 동안 모든 단위 테스트를 시작했습니다.

깨지기 쉬운 테스트를 피하기 위해 다음과 같은 팩토리를 만들었습니다.

이 두 가지 모두 기본값을 제공하므로 특정 테스트에 관심있는 데이터 만 생성하기 위해 속성을 개별적으로 재정의 할 수 있습니다.

내가 사용한 방법은 다음과 같습니다.

참고 : 단위 테스트에는 테이프가 단순하기 때문에 사용합니다. 또한 2 ~ 3 년 동안 Mocha와 Jasmine에 대한 경험과 기타 여러 프레임 워크에 대한 기타 경험이 있습니다. 선택한 모든 프레임 워크에 이러한 원칙을 적용 할 수 있어야합니다.

중첩 테스트를 설명하기 위해 개발 한 스타일에 유의하십시오. 아마도 Jasmine과 Mocha를 사용한 배경 때문에 테스트하려는 구성 요소를 외부 블록에서 설명하고 내부 블록에서 구성 요소에 전달할 대상을 설명하는 것으로 시작하고 싶습니다. 내부에서는 테스트 라이브러리의`deepEqual ()`또는`toEqual ()`함수로 수행 할 수있는 간단한 동등성 어설 션을 만듭니다.

보다시피,`beforeEach ()`와`afterEach ()`와 같은 유틸리티 대신 분리 된 테스트 상태와 팩토리 함수를 사용합니다. 경험이없는 개발자가 테스트 스위트에서 공유 상태를 사용하도록 장려 할 수 있기 때문에 피합니다. .

아마 짐작 하셨겠지만, 각각의 리듀서에 대해 3 가지 종류의 테스트가 있습니다 :

  1. 예를 들어 보았던 직접 감속기 테스트. 이들은 본질적으로 감속기가 예상되는 기본 상태를 생성하는지 테스트합니다.
  2. 액션 생성기 테스트-미리 결정된 상태를 시작점으로 사용하여 감속기를 액션에 적용하여 각 액션 생성자를 테스트합니다.
  3. 선택기 테스트-선택기를 테스트하여 예상 값이있는 계산 된 속성을 포함하여 모든 예상 속성이 있는지 확인합니다.

이미 감속기 테스트를 보았습니다. 다른 예를 살펴 보겠습니다.

액션 크리에이터 테스트

이 예제는 몇 가지 이유로 흥미 롭습니다. `addChat ()`액션 크리에이터는 순수하지 않습니다. 즉, 값 재정의를 통과하지 않으면 생성 된 모든 속성을 구체적으로 기대할 수 없습니다. 이 문제를 해결하기 위해 파이프를 사용했습니다. 파이프는 실제로 필요하지 않은 추가 변수를 만들지 않기 위해 사용합니다. 생성 된 값을 무시하기 위해 사용했습니다. 우리는 여전히 그것들이 존재하는지 확인하지만 그 가치가 무엇인지는 상관하지 않습니다. 유형을 확인조차하지 않습니다. 이를 처리하기 위해 형식 유추와 기본값을 신뢰하고 있습니다.

파이프는 각각 이전 함수의 출력을 취하여 어떤 방식 으로든 변환하는 일련의 함수를 통해 일부 입력 값을 셔틀 할 수있는 기능 유틸리티입니다. lodash / flow /의 별칭 인 lodash / fp / pipe의 lodash 파이프를 사용합니다. 흥미롭게도`pipe ()`자체는 감속기 함수로 만들 수 있습니다.

상태 전환을 단순화하기 위해 감속기 파일에서`pipe ()`를 많이 사용하는 경향이 있습니다. 모든 상태 전이는 궁극적으로 하나의 데이터 표현에서 다음 데이터 표현으로 이동하는 데이터 흐름입니다. 바로`pipe ()`가 좋은 것입니다.

액션 생성기를 사용하면 모든 기본값을 무시할 수 있으므로 특정 ID 및 타임 스탬프를 전달하고 특정 값을 테스트 할 수 있습니다.

선택기 테스트

마지막으로 상태 선택기를 테스트하고 계산 된 값이 올 바르고 모든 것이 올바른지 확인합니다.

이 테스트에서는`Array.prototype.reduce ()`를 사용하여 몇 가지`addChat ()`동작 예제를 줄였습니다. Redux 감속기의 가장 큰 장점 중 하나는 일반 감속기 기능이므로 다른 감속기 기능으로 수행 할 수있는 모든 기능을 수행 할 수 있습니다.

우리의 '예상 된'값은 모든 채팅 개체가 로그에 있고 최근에 활성화 된 사용자가 올바르게 나열되는지 확인합니다.

그것에 대해 말할 것도 많지 않습니다.

리덕스 규칙

Redux를 올바르게 사용하면 다음과 같은 주요 이점이 있습니다.

  • 타이밍 의존성 버그 제거
  • 결정적 뷰 렌더 사용
  • 결정적 상태 재현 가능
  • 간편한 실행 취소 / 다시 실행 기능 사용
  • 디버깅 단순화
  • 시간 여행자가 되십시오

그러나 그 중 하나가 작동하려면 몇 가지 규칙을 기억해야합니다.

  • 감속기는 순수한 기능이어야합니다
  • 감속기는 자신의 국가에 대한 유일한 진실의 원천이어야합니다
  • 감속기 상태는 항상 직렬화 가능해야합니다
  • 감속기 상태에는 기능이 없어야합니다

또한 명심하십시오 :

  • 일부 앱에는 Redux가 필요하지 않습니다
  • 활동 유형에 상수 사용
  • 액션 제작자를 사용하여 디스패치 발신자와 액션 로직을 분리
  • 자체 설명 서명에 ES6 매개 변수 기본값 사용
  • 계산 된 상태 및 디커플링에 선택기를 사용하십시오.
  • 항상 TDD를 사용하십시오!

즐겨!

DevAnywhere로 Redux 기술을 향상시킬 준비가 되셨습니까?

1 : 1 멘토십으로 고급 기능 프로그래밍, React 및 Redux를 배우십시오. 평생 액세스 회원은 기능 프로그래밍 및 Redux 레슨을 확인하십시오. React 및 Redux를 사용하여 실제 앱을 빌드하는 동안 Shotgun 시리즈를 시청하고 Shotgun을 타고 가십시오.

https://devanywhere.io/

Eric Elliott는“JavaScript 응용 프로그램 프로그래밍”(O'Reilly)의 저자이며 DevAnywhere.io의 공동 설립자입니다. 그는 Adobe Systems, Zumba Fitness, The Wall Street Journal, ESPN, BBC 및 Usher, Frank Ocean, Metallica 등을 포함한 최고의 레코딩 아티스트를위한 소프트웨어 경험에 기여했습니다.

그는 세계에서 가장 아름다운 여성과 함께 원하는 곳 어디에서나 일합니다.