Redux(리덕스) - 1에 이어서...
인수로 전달된 state
는 전체를 의미한다는 것에 주의해야 한다. 카운터의 예를 다시 보면,
{
value: 2,
}
위 코드가,
<Counter value={2} />
로 들어가길 바라면서 state => ({ value: state.value })라고 썼다. 이 예에서는 다른 property가 없기 때문에 state => state
라고 써도 동작에는 무리가 없겠지만, 기본적으로 필요한 것만 선별하여 props
로 엮는다가 원칙이라고 생각해야한다.
Action Creator
에서 action
을 만든다고 하더라도, 그것으로는 아무런 일이 일어나지 않는다. Reducer
를 향해 통지를 할 수 있게 만들기 위해서는 만든 action
을 dispatch
라는 함수에 넘겨줘야 한다. 이렇게 하면 모든 Reducer
가 실행된다. Reducer
에 switch문으로 분기를 나눈 것은 바로 이 때문이다. Reducer
는 관계없는 action
을 무시하고, 자기에게 주어진 action
만을 처리하도록 되어있어야만 한다.
또한, Component 쪽에 하나하나 수동으로 dispatch
하는 처리를 하지 않아도 되도록, 여기에서 action
의 생성부터 dispatch
의 실행까지 한번에 이뤄질 수 있도록 함수를 정의하여 props
에 넘겨주도록 한다는 멋진 존재 의의도 엿볼 수 있다.
mapDispatchToProps
를 이용해서 위와 같은 코드를 짜는 것에서 탈출 할 수 있다. bindActionCreatirs
라는 함수를 제공하기 때문이다. 이것을 쓰면 아래와 같은 생략이 가능하다.
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { addValue } from './actions';
const Counter = ({ value, addValue }) => (
<div>
Value: {value}
<a href="#" onClick={e => addValue(1)}>+1</a>
<a href="#" onClick={e => addValue(2)}>+2</a>
</div>
);
export default connect(
state => ({ value: state.value }),
dispatch => bindActionCreators({ addValue }, dispatch)
)(Counter)
// 현재는 bindActionCreators의 실행도 생략할 수 있게끔 되었다.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addValue } from './actions';
const Counter = ({ value, addValue }) => (
<div>
Value: {value}
<a href="#" onClick={e => addValue(1)}>+1</a>
<a href="#" onClick={e => addValue(2)}>+2</a>
</div>
);
export default connect(
state => ({ value: state.value }),
{ addValue }
)(Counter)
지금까지는 '연결된 Component'라고 불렀지만, 상황에 따라서 'Container'라고 불려야하는 Component도 나온다. 수많은 Component가 리스트 형식으로 모여있는 가운데 각 요소의 Component를 각각 연결하면 수습이 안되므로, 대표적인 자식 요소를 안고 있는 하나의 부모 Component가 connect
되는 경우이다.
<UsersList>
<User />
<User />
<User />
<User />
</UsersList>
이 대표로서 connect
될 부모 Component를 Container라고 부른다. Container는 가독성을 높이기 위해서 Component와는 디렉토리를 따로 나누는 경우가 많다.
아직 React+Redux만으로는 불편한 경우가 많다. Reducer
안에 부작용이 생길 처리를 써선 안 된다라는 원칙이 있기 때문이다.
이런 것들은 기본적으로 Reduecer
안에서 쓸 수가 없다. 그럼 대체 어디에서 써야할까?
"또 안티패턴이야? 그럼 넌 Saga란다 ^^"
지금까지 connect
된 Component로부터 action이 dispatch
되면 그 Reducer를 향한다고만 한정지어 설명했다. 여기에서 새로운 방법을 제시하는 것이 Saga
다. Saga
는 제너레이터 함수이기 때문에, 비동기처리를 간단히 다룰 수 있다.
yield take(ACTION_TYPE)
으로 지정한 action의 발생을 감시한다.yield put(action)
의 결과를 다른 action으로 내보낼 수 있다.기본적으로 이런 것들이 가능하다. 내보낸 action은 Reducer
를 향하게도 할 수 있고 자기 자신의 Saga
에게 다시 올 수도 있고, 자기 외의 다른 Saga
에 보낼 수 있을 지도 모른다.