이번에는 Redux와 Thunk Middleware를 사용해서 프로젝트의 전체적인 구조를 다시 잡아 보겠습니다. [React Native] 인스타그램 UI 만들기 시리즈의 개발환경을 그대로 사용합니다.
라이브러리 설치하기
먼저 리덕스를 구현하는 필요한 라이브러리를 설치합니다. Redux 라이브러리는 이전 글 "Redux로 Counter 앱 만들기"에서도 한번 포스팅했었습니다.
redux 와 react-redux 설치
1 | $ yarn add redux react-redux |
설치가 완료되고 나면 package.json
파일의 내용은 다음과 같습니다.
프로젝트 폴더 구조 만들기
이전 프로젝트에서 사용했던 폴더 구조를 조금 조정하겠습니다. 첫 번째로 src
폴더를 생성합니다. 그리고 App.js
파일과 components
폴더를 src
에 옮김니다. 그다음 Redux에 필요한 ./src/reducers
폴더를 생성합니다. reducers
폴더에는 리듀서 관련 파일을 넣을 것입니다. 마지막으로 루트에 App.js
파일을 생성합니다.
우리가 생성한 폴더 구조는 다음과 비슷해야합니다.
Redux Store 설정하기
Redux 및 개념에 익숙하지 않은 경우에는 redux 문서를 참고하세요.
루트에 있는 ./App.js
파일에 Redux Store를 만듭니다 . Store에는 앱에 필요한 모든 데이터가 저장됩니다. 그리고 앱은 필요한 모든 데이터를 모두 Store에서 가져옵니다.
1 | import { Provider } from 'react-redux'; |
- Reducers 는 단순히 일부 데이터를 반환하는 함수라고 볼 수 있습니다.
- 앱에는 여러 개의 reducers가 있을 수 있습니다. 우리는 이 reducers를 사용하여 가능한 많은 Store 을 구성 할 것 입니다.
- 위의 코드에서 우리는 모든 Reducers를 포함하는 allReducers 객체를 사용하고 있습니다.
createStore
함수를 redux 모듈에서 import 합니다. 그리고createStore()
함수를 사용하여 Store를 생성합니다.
./App.js
파일의 전체 코드는 다음과 같아야 합니다.
1 | import React, { Component } from 'react'; |
App.js
파일에서 제일 중요한 App 컴포넌트를 import하여 가져옵니다.- Provider 컴포넌트를 react-redux 모듈에서 import 합니다. 이 컴포넌트는 App 컴포넌트를 하위 컴포넌트로 사용합니다. 그리고 Store 데이터를 App의 모든 부분에서 사용할 수 있도록 해줍니다.
- 마지막으로
store
를 Provider 컴포넌트에 전달합니다. Store는 AllReducers 객체를 전달받아 생성되었습니다.
Redux Reducers 만들기
우리는 하나의 리듀서(reducer)만 만들 것입니다. 그리고 만들어진 steemReducer 리듀서는 스팀잇 API 서버에서 데이터를 가져올 것입니다. ./src/reducers
폴더에 steemReducer.js
파일을 생성합니다.
./src/reducers/steemReducer.js
1 | import { createAction, handleActions } from 'redux-actions'; |
handleActions()
함수에 의해서 정의된 reducer 함수는 state와 action을 인자값으로 전달받습니다.- 앱에서 Action이 전달되는 경우, action은 우리가 만든 모든 Reducers로 보내질 것입다.
마지막으로 모든 reducer를 하나의 개체로 결합할 파일이 필요합니다. reducer
폴더 아래에 index.js
파일을 만듭니다. 지금은 리듀서가 하나라서 불필요한 작업일 수 있습니다. 하지만 리듀서가 여러개일 경우에는 반드시 필요한 작업입니다.
./reducers/index.js
1 | import { combineReducers } from 'redux'; |
Redux Thunk Middleware 사용하기
스팀잇 피드 목록을 가져 오는 작업은 Async operations 에 해당합니다. Async operations 은 오퍼레이션(operation)에 대한 응답이 바로 오지 않습니다. 따라서 Async operations에 대한 응답을 받을때까지 프로그램 실행을 잠시 중단하는 매커니즘이 필요합니다. 비동기로 가져오기 오퍼레이션(Async fetch operation)의 경우에 redux-thunk를 사용합니다.
라이브러리 설치하기
1 | $ yarn add redux-thunk |
미들웨어 설정하기
App.js
파일로 돌아가서 store에 Thunk 미들웨어를 인식 시켜야 합니다.
./App.js
1 | import thunk from 'redux-thunk' |
이제 thunk action을 포함한 모든 actions을 생성할 수 있습니다.
Redux Actions 만들기
리듀서에 fetchFeeds()
함수를 생성합니다. fetchFeeds()
함수는 스팀잇 서버에서 피드를 가져오는 비동기 오퍼레이션을 수행할 것입니다.
./src/reducers/steemReducer.js
1 | export const fetchFeeds = (tag) => { |
Redux components에 적용하기
모든 Redux 설정이 끝나면, 우리는 이제 컴포넌트에서 리덕스를 사용할 수 있습니다. HomeTab.js
파일을 수정합니다.
./src/components/AppTabNavigator/HomeTab.js
1 | import { connect } from 'react-redux'; |
steemReducer
리듀서에서fetchFeeds
액션을 import 하였습니다.mapStateToProps()
함수는 Props에 전달할 값을 정의합니다.steem
리듀서에서feeds
값을 Props에 전달하고 있습니다.mapDispatchToProps()
함수는 Props에 전달할 액션을 정의합니다.- 마지막으로
connect()
함수를 사용하여 컴포넌트와 리덕스를 연결합니다. 이제 Reducers와 Actions를 Props로 전환하였습다.
그다음 componentWillMount()
함수를 수정합니다.
1 | componentWillMount() { |
- 원래
this.fetchFeeds()
함수를 호출하던 부분을 주석처리 하였습니다. - 리듀서 액션
this.props.fetchFeeds()
를 호출하도록 수정합니다.
마지막으로 render()
부분의 컴포넌트를 수정합니다.
1 | render() { |
this.state.feeds
를this.props.feeds
로 수정하였습니다. 이제 스팀잇 피드 가져오는 부분을 리듀서에서 처리하기 때문에, Props에서 가져와야 합니다.- 그리고
<Spinner color='blue'/>
컴포넌트를 추가하여 피드를 가져오기 전에 로딩 이미지가 보이도록 하였습니다.
여기까지 작업한 구동 앱 화면입니다.
UI는 달라진 부분이 없어서 변화가 크진 않네요.
작업한 소스코드는 모두 깃허브에 업로드 되어있습니다.
인스타그램UI 형태의 스팀잇 모바일 앱을 원하는 분이 있다면, 개발을 더 진행하여 앱을 완성할 가치는 있을 것 같습니다. 하지만 partiko나 esteem와 같은 훌륭한 스팀잇 모바일 앱이 존재하므로, 저는 다른 형태의 모바일 앱을 개발하는 것이가치 있을 것으로 생각합니다.
그리고 이제 많은 분이 제 블로그 글을 보고 간단한 모바일 앱은 만들 수 있다고 생각합니다. 앞으로 다양한 아이디어를 가진 모바일 앱이 나오길 기대합니다. 개인적으로 스팀이 기반의 모바일 앱이 나오면 더 좋겠습니다. 예를 들어, 스팀잇 기반의 웹툰 서비스가 나오면 좋지 않을까요? 광고 수익과 스팀 저자 보상을 받을 수 있는 플랫폼이라면 괜찮을 거로 생각합니다.
여기까지 읽어주셔서 감사합니다.