웹개발

리덕스는 무슨 일을 할까? (그리고 언제 사용해야 할까?)

별을 보고 걷는 사람 2020. 8. 8. 06:13
 

What Does Redux Do? (and when should you use it?)

Read this to figure out what Redux is for, why it's useful, and when to use it.

daveceddia.com

2017년 10월 25일

 

리덕스에 관해서 머리를 쥐어짜고 있는가? 걱정하지 마라, 당신뿐만이 아니다.

 

자기가 쓰고 싶은 리액트 앱 코드를 쓰는데에 리덕스가 가장 큰 장애물이라고 정말 많은 사람들한테 들었다.

 

이 게시글 끝에 당신은 리덕스가 뭘 위해 있는지, 그리고 그것을 언제 앱에 추가해야 할지 아는 방법에 대해 이해하게 될 것이다.

 

왜?

시작을 열 최고의 질문은 우리가 대체 왜 리덕스를 사용해야 하나?이다.

 

그리고 그 답은 "왜냐면 인터넷에 있는 모든 이들이 그걸 사용하고 있으니까"가 아니다. (이것이 수 많은 사람들이 그것을 사용하는 이유라는 것을 의심하지 않지만 우리는 더 깊이 들어가자.)

 

리덕스가 유용한 이유는 그것이 문제를 해결하기 때문이다.

 

그리고 그것이 해결하는 문제는 "상태 관리"가 아니다. 그것은 심하게 모호하다. 뭐야, 리액트는 이미 상태관리를 하잖아. 리덕스는 상태관리 하는 것을 도와주기는 하지만 그것이 해결하는 문제는 아니다.

 

그것은 데이터 흐름에 관한 것이다.

만약 리액트를 몇 분 이상 사용했다면 아마 프롭과 일방 데이터 흐름에 대해서 알고 있을 것이다. 데이터는 프롭을 통해 컴포넌트 트리를 전해져 내려간다. 이런 컴포넌트가 있다:

App의 상태에 저장된 count는 하나의 프롭으로 전달될 것이다:

데이터가 트리를 다시 올라가려면 콜백 함수를 따라 흘러야 하는데, 그래서 그 콜백 함수는 어느 컴포넌트든지 데이터를 위로 올려주고 싶어하는 컴포넌트에게 전달되어야 한다.

데이터를 색깔있는 전선으로 관련 있는 컴포넌트에 연결된 전기처럼 생각할 수 있다. 데이터는 이러한 전선들을 따라 내려가고 올라가지만 전선들은 가는 공기를 통해갈 수 없다. - 데이터는 트리 안의 각 컴포넌트 사이에서 연결되어야만 한다.

이것은 전부 복습이길 바란다. (그렇지 않다면 여기서 멈추고, 가서 리액트를 배우고 작은 앱들 두어 개를 만들은 후 며칠 후 다시 오라. 진지하게, 리덕스는 리액트가 어떻게 작동하는지 이해할 때까지는 하나도 이해가 안 될 것이다.)

 

 

데이터 흐름의 겹겹

머지않아 당신은 최상위 레벨 컨테이너가 데이터를 좀 가지고 있고 그 4단계 아래의 자식이 그 데이터를 필요로 하는 상황을 맞닥뜨리게 될 것이다. 여기에 모든 아바타들이 강조된 트위터 스크린삿이 하나 있다.

 

사용자의 아바타가 그들의 프로필 데이터의 한 부분으로 저자오디어 있고, 최상위 레벨 App 컴포넌트가 그 사용자를 가지고 있다고 치자. user 데이터를 3개의 모든 Avatar 컴포넌트들로 전달하기 위해서 user 는 그 데이터를 필요로 하지 않는 한 무리의 중간 컴포넌트들을 엮여지나가야 한다.

 

데이터를 저 아래에서 받는 것은 광산 탐험에 바늘을 꽂는 것과 같아. 잠깐, 이건 말이 안 되는데. 아무튼 이건 정말 골치가 아프다.

 

거기에 더해서, 이건 별로 좋은 소프트웨어 디자인이 아니다. 체인에 있는 중간 컴포넌트들은 자기하고는 상관 없는 프롭들을 받아서 넘겨줘야 한다. 이것은 그 체인에서 컴포넌트들을 재분해하고 재사용하는 것이 필요 이상으로 더 어려워질 것이라는 것을 의미한다.

 

그 데이터를 필요로 하지 않는 컴포넌트들이 그 데이터를 아예 보지 않아도 된다면 더 좋지 않겠는가?

 

어떤 데이터든지 아무 컴포넌트에게 꽂아라

이것이 리덕스가 해결하는 문제이다. 리덕스는 컴포넌트가 필요한 데이터에 직접 접근할 수 있게 해준다. 

 

리덕스와 같이 오는 connect 함수를 사용하여 당신은 어떤 컴포넌트든 리덕스의 데이터 저장소에 꽂을 수 있고, 그 컴포넌트는 필요한 데이터를 꺼낼 수 있다.

이것이 리덕스의 존재의 이유이다.

 

응, 리덕스가 또 뭐 다른 멋진 것들도 하긴 한다. 디버깅을 쉽게 해준다든가 (리덕스 데브툴은 상태 변화를 모조리 검열할 수 있게 한다), 시간 여행 디버깅이라든가 (상태 변화들을 되덜려서 앱이 과거에 어떻게 생겼었는지 볼 수 있다), 그리고 장기적으로 당신의 코드를 더 유지 보수 가능하게 만들어줄 수 있다. 함수적 프로그래밍에 관해서도 더 가르쳐줄 수 있다.

 

그러나 여기 이것, "어떤 데이터든 아무 컴포넌트에나 꽂기"가 주요 행사이다. 이것이 필요 없다면 리덕스가 필요 없을 것이다.

 

Avatar 컴포넌트

이 모든 것을 코드와 연결시키기 위해, 위의 Avatar 컴포넌트 예시가 있다:

import React from 'react';
import { connect } from 'react-redux';
const Avatar = ({ user }) => (
  <img src={user.avatar}/>
);
const mapStateToProps = state => ({
  user: state.user
});
export { Avatar };
export default connect(mapStateToProps)(Avatar);

이 컴포넌트 자에는 리덕스를 알지 못한다 - 이것은 그냥 user 프롭을 받아서 아바타 이미지를 구현한다. mapStateToProps 함수는 리덕스의 창고에서 user를 추출하여 user 프롭과 맵핑한다. 마지막으로 connect 함수가 리덕스로부터의 데이터를 mapStateToProps를 통해 Avatar로 먹여준다.

 

마지막에 export가 두개 있는 것을 눈치챘을 것이다 - 이름이 있는 것과 기본. 이것은 엄격하게 필요하진 않지만, 원래 컴포넌트 및 그것의 리덕스로 감싸진 버전에 접근할 때 유용할 수 있다.

 

원래 컴포넌트는 유닛 시험을 쓸 때 갖고 있으면 유용하고 재사용성도 높여줄 수 있다. 예를 들어, 앱의 일부는 Avatar를 로그인 한 사용자가 아닌 다른 사용자를 위해 구현하고 싶을 수도 있다. 그 경우 한 발짜국 더 나아가, 리덕스와 연결된 버전을 CurrentUserAvatar로 내보내기 해서 코드를 더 명확히 할 수 있다.

 

언제 리덕스를 추가할지

위와 같은 컴포넌트 구조를 가지고 있다면 - 프롭들이 많은 레이어들을 통해 전달되는 - 리덕스 사용을 고려해보라.

 

뷰들 사이에서 데이터를 캐싱 해야 할 필요가 있다면 - 예를 들어 사용자가 상세 페이지를 클릭할 때 데이터를 적재하고 그 데이터를 기억하여 다음 접속이 빠르게 하는 것 - 그 데이터를 리덕스에 저장하는 것을 고려해보라.

 

만약 당신의 앱이 크고 어마어마한 데이터를 보유하고 있다면, 관계형이든 아니든 리덕스 사용을 고려해보라. 하지만 리덕스 없이 시작해 보고 그게 도움이 될 상황에 마주할 때 넣는 것도 생각해보라.