React에 Redux 적용하기(2)

Jo Seung Hyun
10 min readAug 11, 2018

--

Prerequisites

React에 Redux 적용하기(1)

Project 가져오기

- git clone https://github.com/Joe1220/project.git
- cd project
- git reset --hard f6481438ae1d7db80830245f414f0f39cdbd5a4c
- yarn install
- yarn start

해당 프로젝트에 간단하게 리덕스를 적용해보자. 두가지 라이브러리를 먼저 설치한다.

yarn add redux react-redux

프로젝트를 진행할 때는 개인적으로 선호하는 Ducks Pattern을 이용하겠다.우선 src폴더안에 redux폴더와 modules 폴더, 그리고 configureStore.js 파일을 생성하겠다.

structure

modules폴더는 리듀서들을 위한 것이고, configureStore.js는 store의 역할을 할 것이다. modules 폴더 안에 제품을 위한 products.js을 생성해보겠다.

products.js

리듀서 파일은 차례대로

  • import: 필요한 library, file등을 import 한다
  • actions: 상수로 actions의 type을 지정한다
  • action creator: 정의된 action type에 따라 return값을 반환
  • API Actions: 실제 프로젝트는 서버의 api와 같이 운영된다. 서버로부터 받은 data를 통해 action을 실행하게 해준다.
  • initialState: 프로젝트를 실행할 때 default로 얻을 수 있는 state
  • reducer: action type에 따라 reducer function을 실행시켜준다
  • reducer function: action으로 얻은 data를 state로 가져올 수 있다.
  • exports: 실행을 위해 export 시키는 용도

로 작성하게 된다. 각각의 코드를 실행되는 순서대로 살펴보도록 하겠다.

3 line: 서버가 아닌 local에 있는 data를 사용하기 위해 import하였다.22 line: api로 data를 fetch하는 함수이다. 실제 프로젝트에서는 서버와 작동하겠지만, 지금 프로젝트에서는 서버가 없기 때문에.... 조금 괴랄한 함수가 만들어졌다. 실제로 24번째 줄에 fetch는 어떠한 data도 가져오지 못한다. 대신, 30번째 줄에서 .then(response => data)라는 임시방편을 통해 local data를 가져오게 하였다. 실제 프로젝트에서는 이러면 안되겠다...31 line: 가져온 data를 setProducts 라는 액션 생성자로 전달한다. 7번째 줄에서 정이된 action type에 의해 작동하게 되고, items라는 action을 반환한다.43 line: 작성된 reducer에서 어떠한 action일 때 어떠한 reducer function을 실행시킬지 작성한다.54 line: 위에 작성된 코드들을 통해 실제 state를 가지게 된다.

이렇게 작성된 제품을 위한 리듀서, 혹은 다른 목적을 위한 리듀서들을 만들었다면 이를 store을 통해 합쳐야 한다.

Store 생성

이는 configureStore.js파일에서 작성된다. 그 전에 프로젝트를 진행하는 도움이 되는 몇가지 library을 설치하고자 한다.

- yarn add redux-thunk
- yarn add redux-logger --dev
- yarn add react-router-dom react-router-redux history
- yarn add redux-devtools-extension --dev

react-router-redux 설치 시 오류가 날경우, yarn remove react-router-redux로 삭제한 뒤, yarn add react-router-redux@next로 새로 설치한다.

  • redux-thunk : 리덕스의 middleware는 리액트 어플리케이션 그리고 스토어 사이에 존재한다. 유저가 원할때 리덕스의 store로 action을 비동기적으로 보낼 수 있게 해준다.
  • redux-logger : 리덕스 프로젝트를 진행할 때, console창을 통해 현재의 props, action, state등의 정보를 얻을 수 있게 된다. 개발 모드일 때만 사용하므로 — dev 명령어를 붙여 설치하였다.
현재 프로젝트의 logger

.react-router-dom react-router-redux history: 프로젝트의 url에 따른 router 전환을 위해 설치

.redux-devtools-extension: redux-logger와 마찬가지로 개발을 위한 tool이다.

redux devtool

리덕스를 위한 debugging extension이다. state chart, action, 리듀서, 어플리케이션 작동 순서… 여러 가지를 확인할 수 있다. 이를 사용하기 위해서는 단순히 터미널에서 명령어를 통한 설치뿐만 아니라, Chrome App Store에서 설치가 필요하다.

(사용하는 브라우저의 app store을 확인하고 설치하길 바란다. 개인적으로 chrome, firefox를 사용중인데, 두 브라우저 모두 있다.)

https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd?hl=ko 에서 설치

역시 개발용이기 때문에 — dev 을 붙여 설치한다.

이제 configureStore.js파일을 작성해보자.

configureStore.js
8 line: process에 관해서는 블로그 마지막 부분에 설명하도록 하겠다.14 line: env 변수를 통해 현재 어플리케이션의 상태가 development(개발)일 때만 redux-logger을 불러오고 어플리케이션의 middleware에 적용한다.19 line: 어플리케이션의 모든 reducer을 combine해준다. routing은 프로젝트의 url을 확인할 수 있도록 설정해놓았다. redux-logger에서 확인가능.26 line: 개발 상태와 live server상태일때에 store을 구분한다. 첫번째 argument는 리듀서, 두번째 argument는 middeware를 적용한다. 이 때, 미리 설치하였던 redux-devtools-extension을 적용하기 위해서 이것을 applyMiddleware에 감쌌다.
개발을 위하지 않은 basic한 구조는 31번째 줄을 살펴보면 된다.
29 line: middleware를 적용할 때 '...'을 사용하여 배열로 풀어낸다.

store을 만들었으니 실제로 프로젝트에 적용해보겠다.

index.js
9 line: 위에서 작성한 store을 react-redux의 Provider을 통해 어플리케이션에 연결한다. 여기서 Provider는 리듀서의 state를 포함한 스토어를 복사해서 Children Component로 복사해준다.10 line: redux 프로젝트를 위한 router 기능.

리덕스를 위한 설정을 완료하였다. 그렇다면 이를 기존의 Component에 어떻게 연결할까? 그러기 위해서는 기존에 구조를 약간 수정해야 한다.

Component Pattern

기존에 있던 App Component의 구조를 변경해보도록 하겠다.

App Component Structure

기존에 App.js와 App.css 두개의 파일에서 4개의 파일을 통해 Component를 구성하겠다.

presenter.js: view기능만을 담당
container.js: method같은 logic을 담당
index.js: 리듀서와 연결해준다
presenter.js

기존 코드와 다르게 오직 view의 역할만 하고 있다. 기존 App.js의 로직은 container.js로 전환하였다.

container.js

리듀서를 포함한 스토어와 연동하는 파일은 index.js이다.

index.js파일을 좀 더 구체적으로 살펴보겠다.

1 line: connect는 Component를 스토어에 연결해주는 것을 돕는다.2 line: 작성한 리듀서를 productionActions라는 별명을 가지게 한 뒤 불러왔다.12 line: mapDispatchToProps는 리듀서에서 생성한 액션을 받아와서 props로써 사용할 수 있게 해주는 함수이다. 5 line: 잠시 container.js파일의 18줄을 살펴보면 액션을 받아와서 새로 생성한 getProducts함수를 실행하고 있다. 해당 함수는 state를 생성하게 되며, mapStateToProps는 이름 그대로 새로 생성한 items state를 props로써 사용하게 해주는 역할을 하게 된다.20 line: 스토어와 Component의 로직을 담당하는 container.js파일을 연결한다.

여기까지 작성하였다면, 우리의 프로젝트는 정상작동하나, 한가지 문제가 생긴 것을 확인할 수 있다. url 변경 시 즉각적인 리렌더링이 되지 않는다.

Update Blocking

Update Blocking은 Component가 렌더링이 정상적으로 렌더링이 되지 않는 것을 뜻한다. url을 변경할 때마다 Component가 새로운 렌더링을 해야 하는데, 우리의 어플리케이션이 변경된 location을 인지 못해서 생기는 문제이다.

이를 해결하기 위해서는 최상단 Component인 App의 index.js파일을 수정하면 된다.

App Component의 index.js
7 line: Component로 하여금 location을 인식시켜줌으로써, 해당 문제를 해결할 수 있다. 나의 App Component는 새로운 location prop의 존재를 인식하고, location이 바뀔 때마다 렌더링을 하게 된다.

이제 configureStore.js파일의 8번째 줄에 있던 process에 대해 설명하도록 하겠다.

Process.env

우선 console.log를 통해 process안에 무엇이 있는지 살펴보자.

console.log(process)

process는 객체로써 컴퓨터가 가지는 환경에 대한 정보를 포함하고 있고 다양한 method를 가지고 있다. 그렇다면 process.env를 출력하면 어떻게 될까?

console.log(process.env)

보다시피 어플리케이션의 상태를 알 수 있게 된다.

process.env 는 Node 어플리케이션이 동작하는 시스템의 환경변수를 위한 전역 변수이다. 이를 통해 우리는 development(개발) 상태, 혹은 서버에서 작동되는 상태를 구분해서 우리의 프로젝트를 진행할 수 있게 되는 것이다.

이것으로 React에 Redux 적용하기 블로그를 마치겠다.

전체 코드를 확인하고 싶다면, 아래 코드를 참조하길 바란다.

- git clone https://github.com/Joe1220/project.git

--

--