리액트 상태관리 - Redux를 이용해보자

2019. 5. 29. 21:26ReactJS

Redux?

우리는 리액트의 state 관리하는 것과 UI와의 일관성 유지하는 게 중요하다는 것을 알고?있습니다. (중요합니다ㅎ)
그런데 웹 애플리케이션이 훨씬 복잡해지고 많은 계층구조가 생기면(부모-자식-손자-증손자...) state관리는 극혐이됩니다.

 각 계층은 자신이 가지는 기능을 해야하고 그 기능 수행을 위해 어떤 관계에서는 state를 가져와 사용하는 의존관계가 심화될 수 있습니다. 밑의 그림을 보면 서로서로 아주 격렬하게 의존관계가 생성됨을 알 수 있습니다...

 

출처 : http://www.liberaldictionary.com/redux/

애플리케이션 'state관리'라는 문제를 좀 해소시켜보자 해서 'Redux'라는 게 등장했습니다. 

위의 그림을 보면 리덕스는 애플리케이션의 state를 다루고 저장하는 마법을 애플리케이션에 부여하는 일만 신경씁니다.

그리고 그것을 '스토어(store)'라는 단일 저장소에 저장합니다!

 

 

/ 애플리케이션 - 스토어 / 간 직접적인 처리가 아닌 

/ 애플리케이션 - 액션 - 리듀서 - 스토어 - 애플리케이션 / 이렇게 우회적으로 처리합니다.

 

 * 액션 : 스토어에 새로운 state정보를 추가하거나 기존 state를 변경하는 일은 무엇이 변경된 지 기술하는 것

   리듀서 : 액션의 결과로 최종 state를 결정한다.

 

우회적 처리.. why?

확장성 때문! 리덕스는 애플리케이션의 상태를 쉽게 저장하고 예측 가능하게 관리해줍니다.

 

리덕스의 철학

1. 앱의 모든 state는 한 장소에 저장. 즉, state를 갱신하려고 여기저기 찾아다닐 필요가 없다!

2. state는 오직 readable. 즉, 읽기 전용이고 액션을 통해서만 변경한다. 데이터 변경하는 유일한 방법이 액션!

3. 반!드!시! 마지막 state가 저장돼야 한다. state는 결코 수정, 변형 않는다는 말이다. 따라서 리듀서를 이용해 마지막 state값을 지정한다.

 


 

액션 생성자 (return action)

function addColor(value){
	return{
    	type : 'add',
        color: value
    }
}

function removeColor(value){
	return{
    	type: 'remove',
        color: value
    }
}	

위에서 2개의 메서드는 각각 액션을 리턴합니다.  액션 객체는 type속성과 color속성을 담고 있네요 :)

이렇게 액션을 리턴하는 메서드를 리덕스 세계에서는 '액션 생성자'라고 지칭합니다.(because 액션을 생성하니까 ^^;;) 


이제 리듀서 time!

액션이 하고자 하는 일을 정의한다면/ 리듀서는 그 일이 무슨 일인지와 새로운 state를 정의하는 방법을 구체적으로 다룹니다. 즉, 리듀서는 스토어(store)와 바깥 세상의 중개자 정도로 생각하면 좋습니다

 

중개자의 일

1. store의 원래 state에 접근할 수 있게 해준다.

2. 현재 발생된 action을 조사할 수 있게 해준다.

3. store에 새로운 state를 저장할 수 있게 해준다.

 

정도로 보면 좋겠습니다.

 

리듀서(Reducer)

리듀서를 작성해봅시다!

function reducerColors(state, action){
	// 상태 객체가 존재하지 않으면 상태 객체를 빈 배열로 초기화합니다.
	if(state === undefined){
    	state=[]
    }
    // 밑으로는 액션을 다루는 코드로 인자로 액션 객체를 그대로 받는다..
    // 이것은 액션의 type뿐 아니라 속성이 추가되도 모든 정보에 접근할 수 있다는 뜻!
    if(action.type === 'add'){
    	return state.concat(action.color)
    }
    else if(action.type === 'remove'){
    	return state.filter(item => { return item !== action.color })
    }
    else {
    	reutrn state
    }

}

리듀서을 작성해 봤는데 리듀서 안에서 절!대! 하지 말 사항들이 있다.

  • 받은 인자의 변형
  • API호출이나 라우팅 변경 등 같은 추가적인 기능 구현
  • Date.now(), Math.random()같은 비순수 함수 호출

리듀서는 오직 주어진 인자로 다음 state를 산출해서 리턴! 추가구현x / api호출x / 변형x ... 오직 산출만!!

 

위의 코드에서도 state.push()를 쓰면 기존의 배열을 변형하므로 규칙에 위배된다.

하지만 concat()은 완전 새로운 배열을 새로 리턴하므로 괜찮다:>

마찬가지로 filter()도 조건에 따라 값을 제거 후 새로운 배열을 새로 리턴하므로 규칙을 위반하지 않았다!

 

 


스토어(store)

 

action과 reducer를 작성했다면 이제 남은 건 action과 reducer를 스토어에 엮는 일입니다

그럴러면 일단 스토어를 만듭시다!

 

var store = Redux.createStore(reducerColors)

createStore  -  스토어를 생성. 인자는 리듀서를 받음.

이렇게 리덕스를 통해 앱의 state를 저장하는 과정의 한 싸이클을 돌았습니다.

즉, store가 있고 / reducer가 있으며 / reducer가 해야 할 일을 알려주는 action을 갖추게 되었습니다.

 

모든 사항이 잘 작동하는 지 확인을 위해 color를 추가하거나 제거해봅니다.

액션을 인자로 받는 dispatch()를 store객체에 사용합니다.

store.dispatch(addColor("blue"))
store.dispatch(addColor("red"))
store.dispatch(addColor("green"))
store.dispatch(removeColor("blue"))

dispatch()를 호출하면 action을 reducer로 전달합니다. reducer는 action을 받아서 state를 정의하기 위한 적절한 동작을 합니다! store의 현재 상태를 확인하려면 다음과 같이 콘솔에 찍어봅니다.

console.log(store.getState())

 

 


현실에서 앱은 상태가 변할 때마다 이것을 인지하고 싶어할 것입니다.

그러한 push모델은 store의 어떤 변경으로 인한 결과로 UI를 갱신하거나 다른 작업을 수행할 때 유용합니다.

그렇게 하기 위해서 특정함수를 store에 등록하여 변경이 있을 대마다 호출할 수 있습니다.

 

다음과 같이 작업을 해주자!

var store = Redux.createStore(reducerColors)

// dispatch를 호출할 때마다 각자 다른 action으로 store가 변경되며 
// render함수를 호출 할 수 있을 것입니다!
store.subscribe(render)

function render(){
	console.log(store.getState())
}

 


리액트 앱에 리덕스를 적용하는 방법은 리액트 코드에서 리덕스API를 호출만 하면 될 정도로 직관적. 다음 2단계만 보자

 

  1. 앱이 리덕스 스토어를 참조하게 한다 (리액트앱에서 리덕스를 사용하는 관문 역할의 Component)
  2. 스토어의 데이터를 필요로 하는 컴포넌트의 액션생성자 / dispatch()함수 / state를 속성으로서 매핑한다               (전통적인 Component가 아닌 고차원 Component (HOC로 줄여 부른다)로 리덕스 스토어와 작업을 위해 액션과 디스패치에 접근하게 해주는 Component)   

 

이 두 가지를 도와줄 컴포넌트를 생성. 

 

redux 자체와 의존성 패키지를 설치

// 리덕스 자체를 설치. 설치 후 리덕스에서 제공하는 빌딩 block 사용 가능!
npm install redux

// 의존성 패키지도 설치
npm  insatll react-redux

 

 

 

참고 

learning react 2/e

<Redux로의 카툰 안내서> -  https://bestalign.github.io/2015/10/26/cartoon-intro-to-redux/

'ReactJS' 카테고리의 다른 글

[Next.js] Next.js 정리 노트  (0) 2021.02.01
SPA (Single Page Application)  (0) 2019.05.29
[ReactJS] DOM Element 접근  (0) 2019.05.26
[ReactJS] React Component LifeCycle API  (0) 2019.05.20
[ReactJS] state / props  (0) 2019.05.19