[2] 리액트 네이티브에 리덕스 적용하기

하루한줌땅콩·2022년 5월 2일
0
post-thumbnail

리덕스의 첫번째 포스팅에선 리덕스에 대한 개념 위주의 소개글을 적었었다.
하지만 실질적으로 리액트 네이티브에 어떻게 적용이 되는지 알아야 사용할 수 있지 않은가. 그래서 현재 나의 경험을 토대로 리덕스를 어떻게 사용하고 있는지 적어보겠다.

우선 간단하게 다시 개념을 복기하면..
상태 정보(state)를 저장하는 공간인 store
상태 정보를 수정하는 (완전히 뒤바꾸는) 유일한 도구인 reducer
그리고 action (상태 수정 요청) 을 데리고 다니는 dispatch 가 있었다.
개념은 헷갈릴 수 있지만 예시를 보면 금방 이해할 수 있을 것이다.

우선 본 포스팅에서 나아가 더 많은 정보를 알고 싶으면
리덕스 공식 홈페이지 https://lunit.gitbook.io/redux-in-korean/ 를 참고하시길!

폴더구조

Store - actions - authActions.js

      - reducers - index.js
      			 - authReducers.js   
      - types.js

예시로 사용자 로그인, 회원가입 정보에 대한 상태를 관리해보겠다. actions를 정의하기 전 action들의 type을 작성하자. 이는 types.js에 작성한다.

<types.js> 
export const SIGN-IN = "sign-In" 
export const SIGN-UP = "sign-up"

action은 상태를 어떻게 해달라는 요청이라고 볼 수 있다. 모든 요청에는 어떤 요청인지에 대한 자기만의 이름이 부여되어있다. 그게 actions의 type 이다. types.js에는 redux 관리 창에 보이는 action type에 대한 string 값이 저장되어있다.

즉 예를 들어 SIGN-IN 은 actions의 type이 될 것이고 'sign-in" 은 SIGN-IN 이라는 action이 불릴때마다 redux 관리 창에 보여지는 이름이 된다.

이번에는 실제 actions들을 작성해보겠다.

<authActions.js>
import {SIGN_IN, SIGN_UP} from '../types'

export function signIn(data) { 
   return {
         type: SIGN_IN,
         payload: {
            phone: data.phoneNumber,
            authenticationNumber:data.authenticationNumber
        }     
 }
 
 export function signUp(data) { 
 
   return {
         type: SIGN_UP,
         payload: {
            name: data.name, 
            email: data.email, 
            sex: data.sex
        }     
 }

현재 로그인과 회원가입에 대한 action을 만들어보았다.
signIn 이라는 action은 type과 payload가 포함된 객체를 return 한다. type은 이전에 말했듯이 요청의 이름이고, payload는 요청할때 보내주는 자료이다. 이 자료를 reducer가 받아서 store에 저장되어 있는 state 값을 변경해준다.

signIn(data) -> {type / payload: {data.phone, data.authen..}}

이제 reducer를 작성해보자. reducers 폴더의 하위 파일인 authReducer.js 를 보자. reducer는 action의 요청을 받아 실질적으로 state를 수정하는 역할을 한다. 이전의 포스팅에서 state를 수정한다기보다는 통째로 바꾼다고 했는데, 아래의 reducer의 모습을 보면 그 이유를 알 수 있다.

<authReducers.js>
import {SIGN_IN, SIGN_UP} from '../types'

export default function(state={}, action) {
    switch(action.type) {

        case SIGN_IN: 
            return {
                ...state,
                auth: {
                    phone: action.payload.phone || false,
                    authenticationNumber: action.payload.authenticationNumber || false 
                    
                }
            }

        case SIGN_UP: 

            return {
                ...state,
                auth: {
                    phone: state.auth.phone,
                    authenticationNumber: state.auth.authenticationNumber, 
                    name: action.payload.name || false,
                    email: action.payload.email || false,
                    sex: action.payload.sex || false, 
                    
                }
            }   
    	defualt: 
        	return state 
     }
}

reducer는 현재의 state와 action을 매개변수로 받는다. 초기의 state는 빈 object로 setting 되어있다. state={}. 이후, 코드를 보면 reducer는 switch문을 통해 어떤 action 인지 판별한다.

현재 사용자의 입장에서는 SIGN_IN 후 SIGN-UP 을 한다. 원래대로라면 SIGN-UP이 회원가입, SIGN-IN이 로그인이라 SIGN-UP 후 SIGN-IN의 순서가 맞지만 그 부분은 양해부탁한다..

각설하고, SIGN_UP case의 return 값을 보자. return 값은 object로 {... state, auth: { 새로운 내용 }} 의 형태를 띤다. 즉, 기존의 state 위에 새로운 내용을 덮어쓰기 하겠다는 의미이다. (통째로 바꾼다!)

SIGN_IN에서 받은 phone과 authenticationNumber는 SIGN_UP에서도 가져가야하는 (필요한) 정보이므로

phone: state.auth.phone,
authenticationNumber: state.auth.authenticationNumber
의 정보가 return값에 포함되어있는 것을 볼 수 있다.
만일 SIGN_UP return값에 phone과 authenticationNumber에 대한 정보가 없다면 SIGN_IN이 끝나고 SIGN_UP이 되었을때 store에는 phone, authenticationNumber가 사라지고 name, email, sex에 대한 정보만 남아있을 것이다. 이러면 state에 정보를 보관하는 의미가 없어진다.

action이 보낸 type이 존재하지 않으면 reducer는 원래의 state를 return하게 된다.

reducers 폴더 하위의 index.js에는 reducer들을 통합하고 이름을 붙여줄 수 있는 공간이 마련되어있다.

<index.js>
import { combineReducers } from 'redux'; 
import User from './auth_reducer';

const rootReducer = combineReducers ({
    User
});

export default rootReducer; 

현재 우리의 예제에서는 Authentication에 대한 reducer인 auth_reducer 만 만들었지만, 사실 reducer는 여러 종류일 수 있다.
예를 들면 사용자의 대여 반납 정보인 borrow_reducer, return_reducer도 만들 수 있는 것이다. 이렇게 reducer의 종류를 나눠놓으면 state를 관리하기 매우 용이해질 것이다.

index.js를 보면 auth_reducer를 User라는 이름으로(내가 지정한 이름!)import 했고 이를 combineReducers 라는 redux의 함수를 통해서 묶어주었다.

이전에 auth_reducer에서 auth라는 하위 카테고리에 정보를 지정했던 것이 기억나는가? 그렇다면 redux의 state가 어떻게 표현되는지 알아보자!

SIGN_IN과 SIGN_UP을 거치면 우리는

User - auth { phone ~, authentica... ... sex ~ }

의 state를 갖게 된다.

지금까지 action과 reducer의 개념을 토대로 실질적인 생김새?에 대해서 살펴보았고, 어떤 원리로 동작하는지 알아보았다. 다시 쉽게 정리하면 우리는 어떤 요청에 따라 state를 관리하게 되는데, 그 요청의 이름이 action의 type이다. action은 type과 함께 가공할 재료들인 payload를 reducer에게 가져다준다. (실질적인 component에서 어떻게 이러한 과정이 일어나는지는 3편에서 작성하겠다.) 그러면 reducer는 action이 주는 값을 받아 switch문에서 type을 찾고 가공할 데이터를 가지고 미리 짜여진 양식에 따라 state를 덮어써버린다. rootreducer는 단지 여러개의 reducer를 묶어놓은 함수일 뿐이다.

state 값을 어떻게 가져오는지, 그리고 어떻게 수정하는지에 대해서는 다음 포스팅에서 적어보겠다.

profile
개발기록지

0개의 댓글