설계 결정 사항
이 페이지는 PageTurner AI로 번역되었습니다(베타). 프로젝트 공식 승인을 받지 않았습니다. 오류를 발견하셨나요? 문제 신고 →
Redux FAQ: 설계 결정 사항
Redux는 왜 상태와 액션을 구독자에게 전달하지 않나요?
구독자는 액션이 아닌 상태 값 자체에 반응하도록 설계되었습니다. 상태 업데이트는 동기적으로 처리되지만, 구독자에게 보내는 알림은 일괄 처리(batching)나 디바운싱(debouncing)될 수 있어 모든 액션마다 알림이 전송되지는 않습니다. 이는 반복적인 리렌더링을 방지하기 위한 일반적인 성능 최적화 기법입니다.
store.dispatch를 오버라이드하는 인핸서를 사용하면 알림 방식을 변경하여 일괄 처리나 디바운싱이 가능합니다. 또한 다음 라이브러리를 사용하면 액션을 일괄 처리하여 성능을 최적화하고 반복적인 리렌더링을 방지할 수 있습니다:
-
redux-batch: 액션 배열을
store.dispatch()에 전달하고 단 한 번의 알림만 발생시킵니다. -
redux-batched-subscribe: 디스패치로 인해 발생하는 구독 알림을 일괄 처리합니다.
Redux의 핵심 보장 사항은 모든 구독자에게 최신 상태를 전달하는 것이지, 모든 액션마다 각 구독자를 호출하는 것이 아닙니다. 구독자 내에서 store.getState()를 호출하면 저장소 상태를 바로 확인할 수 있습니다. 액션 일괄 처리 방식을 유지하려면 구독자에게 액션을 제공할 수 없습니다.
구독자 내부에서 액션을 사용하는 사례(공식 지원되지 않음)로는 특정 유형의 액션 이후에만 컴포넌트가 리렌더링되도록 보장하는 것이 있습니다. 대신 리렌더링은 다음 방법들로 제어해야 합니다:
-
shouldComponentUpdate 라이프사이클 메서드
-
React-Redux 사용: mapStateToProps로 컴포넌트가 필요한 저장소 부분만 구독합니다.
추가 정보
아티클
토론
Redux는 왜 클래스를 사용한 액션과 리듀서를 지원하지 않나요?
액션 객체를 반환하는 함수(액션 생성자) 패턴은 객체 지향 프로그래밍 경험이 많은 개발자에게 직관적이지 않을 수 있으며, 클래스와 인스턴스 사용이 더 적합해 보일 수 있습니다. 하지만 클래스 인스턴스는 직렬화(serialization)와 역직렬화(deserialization)를 복잡하게 만듭니다. JSON.parse(string) 같은 역직렬화 메서드는 클래스 인스턴스가 아닌 일반 자바스크립트 객체를 반환합니다.
저장소 FAQ에서 설명한 것처럼, 지속성(persistence)이나 시간 여행 디버깅(time-travel debugging)이 의도대로 동작하지 않아도 괜찮다면 Redux 저장소에 직렬화 불가능한 항목을 넣어도 됩니다.
직렬화를 사용하면 브라우저가 디스패치된 모든 액션과 이전 저장소 상태를 훨씬 적은 메모리로 저장할 수 있습니다. 저장소 되감기(rewinding)와 '핫 리로딩(hot reloading)'은 Redux 개발자 경험과 Redux DevTools의 핵심 기능입니다. 또한 서버 사이드 렌더링 시 서버에서 역직렬화된 액션을 저장하고 브라우저에서 재직렬화할 수 있게 합니다.
추가 정보
아티클
토론
미들웨어 시그니처에 커링을 사용하는 이유는 무엇인가요?
Redux 미들웨어는 단일 함수 형태인 const middleware = (storeAPI, next, action) => {} 대신 const middleware = storeAPI => next => action => {}처럼 삼중 중첩 함수 구조로 작성됩니다. 이에는 몇 가지 이유가 있습니다.
첫째, 함수 "커링"은 표준 함수형 프로그래밍 기법이며, Redux는 설계 시 함수형 프로그래밍 원칙을 명시적으로 채택했습니다. 둘째, 커링 함수는 미들웨어 수명 주기 동안 존재하는 변수를 선언할 수 있는 클로저를 생성합니다(이는 클래스 인스턴스 수명 동안 존재하는 인스턴스 변수의 함수형 동등물로 볼 수 있음). 마지막으로 이 방식은 Redux 초기 설계 당시 선택된 접근법입니다.
일부에서는 커링 함수 시그니처가 불필요하다고 여깁니다. 왜냐하면 applyMiddleware 함수 실행 시점에 store와 next가 모두 사용 가능하기 때문입니다. 그러나 기존 미들웨어 정의에 의존하는 수백 개의 Redux 생태계 미들웨어를 고려할 때, 이 문제는 호환성 차단을 도입할 가치가 없는 것으로 판단되었습니다.
추가 정보
토론
- 미들웨어 시그니처에 커링을 사용하는 이유?
applyMiddleware가 dispatch에 클로저를 사용하는 이유는 무엇인가요?
applyMiddleware는 스토어의 기존 dispatch를 가져와 클로저로 감쌉니다. 이를 통해 getState와 dispatch 함수를 노출하는 객체로 초기화된 미들웨어 체인을 생성함으로써, 초기화 과정에서 dispatch에 의존하는 미들웨어가 실행될 수 있도록 합니다.
추가 정보
토론
combineReducers가 각 리듀서를 호출할 때 전체 상태를 세 번째 인자로 포함하지 않는 이유는 무엇인가요?
combineReducers는 도메인별로 리듀서 로직을 분할하도록 권장하는 의도적인 설계입니다. combineReducers의 한계에서 설명하듯, combineReducers는 단일 공통 사용 사례(일반 자바스크립트 객체인 상태 트리를 특정 슬라이스 리듀서에 위임하여 업데이트)를 처리하도록 의도적으로 제한됩니다.
각 리듀서에 대한 세 번째 인자로 전체 상태 트리, 콜백 함수, 상태 트리의 다른 부분 등을 전달하는 것은 명확하지 않습니다. combineReducers가 사용 사례에 맞지 않는다면, combineSectionReducers나 reduceReducers 같은 라이브러리를 고려해 깊게 중첩된 리듀서나 전역 상태 접근이 필요한 리듀서에 대안으로 사용하십시오.
기존에 공개된 유틸리티 중 사용 사례를 해결할 수 있는 것이 없다면, 필요한 기능을 정확히 수행하는 함수를 직접 작성할 수 있습니다.
추가 정보
아티클
토론
mapDispatchToProps에서 getState() 또는 mapStateToProps()의 반환 값을 사용할 수 없는 이유는 무엇인가요?
전체 state나 mapState의 반환 값을 mapDispatch 내부에서 사용해, mapDispatch 내부에 선언된 함수들이 스토어의 최신 값을 참조할 수 있도록 하려는 요청이 있었습니다.
이 방식은 mapDispatch에서 지원되지 않는데, 그 이유는 스토어가 업데이트될 때마다 mapDispatch를 호출하게 되기 때문입니다. 이는 상태 업데이트마다 함수를 재생성하게 되어 성능에 큰 부하를 초래합니다.
이 사용 사례(현재 상태와 mapDispatchToProps 함수를 기반으로 props를 변경해야 하는 경우)를 처리하는 권장 방식은 connect 함수의 세 번째 인수인 mergeProps를 활용하는 것입니다. 지정된 경우 mergeProps는 mapStateToProps(), mapDispatchToProps()의 결과와 컨테이너 컴포넌트의 props를 전달받습니다. mergeProps에서 반환된 일반 객체는 래핑된 컴포넌트에 props로 전달됩니다.
추가 정보
토론