만족

[React] Redux에서 부적절한 패턴 사용으로 인한 시간낭비 본문

[React] Redux에서 부적절한 패턴 사용으로 인한 시간낭비

FrontEnd/React Satisfaction 2020. 6. 18. 04:07

리덕스는 대표적인 상태 관리 라이브러리다.

 

리액트에서는 여러 컴포넌트가 동시에 사용하는 state를 props를 이용해 하위 컴포넌트로 계속해서 전달하는 대신 하나의 스토어에서 관리하게 되어 생산성을 높이는데 주로 사용된다.

 

잠깐 설명을 하고 가자면, 리액트는 FLUX아키텍쳐를 채택하여 컴포넌트 간 데이터 흐름은

항상 상위 컴포넌트에서 하위 컴포넌트로 흐르게끔 강제한다.

 

그러나 때때로 A Component에서 B Component로 데이터를 넘겨줘야만 할 때가 있는데,

이 규칙을 따르려면 불필요한 래핑을 진행하거나 사용할 데이터를 Parent Component로 옮긴 후, props로 보내주는 방식을 채택해야 한다.

 

컴포넌트간 관계가 소규모라면 어렵지 않지만, 매우 복잡하게 얽혀있는 관계라면 꽤 번거롭고 어려운 작업이 될 것이다.

 

리덕스를 사용하면 위 문제의 해결책을 찾을 수 있다.

 

스토어에 특정 액션을 디스패치하면, 스토어를 구독중인 컴포넌트에게 사이드 이펙트(props가 업데이트됨)를 발생시켜서

마치 컴포넌트의 state를 공유하고 있는 상태처럼 작동하게 된다.

(Dispatch는 컴포넌트의 setState처럼 생각해도 좋다)

 

허나 리덕스도 위에서 말한 작동방식이 정상적으로 이루어지게 하기 위해 store state의 변경은 반드시 Dispatcher를 이용한다특별한 규칙을 강요한다.

다시 말해, Dispatcher를 사용하지 않은 state의 변경은 구독한 컴포넌트에 아무런 사이드 이펙트를 일으키지 않는다.

 

매우 쉬운 규칙이지만... 편한 길로 가려다 보면 때때로 규칙을 무시하게 된다.

 

문제 발생 경위

 

나의 경우에는 redux store에 자주 사용하는 ui component를 제어하는 객체(이하 uiKit)를 최상위 컴포넌트에서 하나 디스패치하고

A Component와 Popup Component가 해당 리덕스 스토어를 구독하는 구조에서

A Component에서 버튼을 누르면 popup 내부에 들어갈 엘리먼트들을 uiKit의 함수를 이용해 전달하여 Popup Component를 렌더링시키는 방법을 사용했다.

 

꽤 문제없이 잘 쓰고 있었으나, 이번에 만든 컴포넌트에서 상태 변화가 일어나지 않는다는 치명적인 문제가 발생했다.

 

uiKit.popup.open(...) 내부에 들어가는 엘리먼트가 popup에 전달되는 구조인데,

문제는 onChange로 발생된 state의 변화를 popup은 모른다는 것이다.

 

email state는 A Component가 관리하므로, email이 변경되면 A Component에만 사이드 이펙트가 발생하고

Popup Component에는 아무런 일도 일어나지 않아 아무리 키보드를 눌러도 위의 value={email}은 초기값에서 변하지 않게 된다.

다시한번 구조를 보면, 분명 A Component의 openPopup함수는 state(이 경우 uiKit)에 변화를 일으키는 함수임에도 Dispatch하지 않고 state를 직접 변형한다.

 

그렇다.... 개쓰레기 안티패턴인것이다....

 

해결법

모두가 잘 알고 있듯이 가장 근본적인 해결책은 구조를 뜯어 고치는 것이다.

 

uiKit에 전달하는 엘리먼트를 하나의 컴포넌트로 치환하고

state는 그 컴포넌트(이하 B Component)에서 관리하도록 하여 Popup에 전달하는 방법이다.

 

그렇게 하면 Popup Component에서 사이드 이펙트는 발생하지 않지만,

Popup 내부에 있는 B 컴포넌트에서는 state의 update로 인한 사이드 이펙트가 발생한다.

 

그러나 uiKit의 함수를 사용해 객체 내부에 Component를 저장하고 표시하는 과정에서 Dispatch하지 않고 store에 저장된 state를 변경한다는 점은 여전히 타당하지 않다.

 

가장 이상적이고 근본적인 방법은

redux에서 하라는 대로, B Component에 대해 디스패치함으로써 store의 state가 업데이트되고 Popup Component가 자동으로 이를 알아차리게 하는 방법이다.

 

오늘은 몇시에 잘 수 있을지 모르겠다...



Comments