TIL | Redux(리덕스) - 2

ryan·2020년 10월 25일
0

React

목록 보기
16/20
post-thumbnail

Redux(리덕스) - 1에 이어서...

mapStateToProps

인수로 전달된 state는 전체를 의미한다는 것에 주의해야 한다. 카운터의 예를 다시 보면,

{
  value: 2,
}

위 코드가,

<Counter value={2} />

로 들어가길 바라면서 state => ({ value: state.value })라고 썼다. 이 예에서는 다른 property가 없기 때문에 state => state라고 써도 동작에는 무리가 없겠지만, 기본적으로 필요한 것만 선별하여 props로 엮는다가 원칙이라고 생각해야한다.

mapDispatchToProps

Action Creator에서 action을 만든다고 하더라도, 그것으로는 아무런 일이 일어나지 않는다. Reducer를 향해 통지를 할 수 있게 만들기 위해서는 만든 actiondispatch라는 함수에 넘겨줘야 한다. 이렇게 하면 모든 Reducer가 실행된다. Reducer에 switch문으로 분기를 나눈 것은 바로 이 때문이다. Reducer는 관계없는 action을 무시하고, 자기에게 주어진 action 만을 처리하도록 되어있어야만 한다.

또한, Component 쪽에 하나하나 수동으로 dispatch하는 처리를 하지 않아도 되도록, 여기에서 action의 생성부터 dispatch의 실행까지 한번에 이뤄질 수 있도록 함수를 정의하여 props에 넘겨주도록 한다는 멋진 존재 의의도 엿볼 수 있다.

bindActionCreators

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)

Container

지금까지는 '연결된 Component'라고 불렀지만, 상황에 따라서 'Container'라고 불려야하는 Component도 나온다. 수많은 Component가 리스트 형식으로 모여있는 가운데 각 요소의 Component를 각각 연결하면 수습이 안되므로, 대표적인 자식 요소를 안고 있는 하나의 부모 Component가 connect되는 경우이다.

<UsersList>
  <User />
  <User />
  <User />
  <User />
</UsersList>  

이 대표로서 connect될 부모 Component를 Container라고 부른다. Container는 가독성을 높이기 위해서 Component와는 디렉토리를 따로 나누는 경우가 많다.

발전

Redux Saga의 도입

아직 React+Redux만으로는 불편한 경우가 많다. Reducer 안에 부작용이 생길 처리를 써선 안 된다라는 원칙이 있기 때문이다.

  • 같은 입력에 대해 확률적으로 다른 결과가 나오는 처리
  • 지연 처리
  • HTTP Request 처리

이런 것들은 기본적으로 Reduecer 안에서 쓸 수가 없다. 그럼 대체 어디에서 써야할까?

  • Component 안
  • Action Creator 안
  • mapDispatchToProps 안

"또 안티패턴이야? 그럼 넌 Saga란다 ^^"

지금까지 connect 된 Component로부터 action이 dispatch되면 그 Reducer를 향한다고만 한정지어 설명했다. 여기에서 새로운 방법을 제시하는 것이 Saga다. Saga는 제너레이터 함수이기 때문에, 비동기처리를 간단히 다룰 수 있다.

  1. yield take(ACTION_TYPE)으로 지정한 action의 발생을 감시한다.
  2. 가져온 action을 구워먹고, 삶아먹고 마음대로 할 수 있다.
  3. yield put(action)의 결과를 다른 action으로 내보낼 수 있다.

기본적으로 이런 것들이 가능하다. 내보낸 action은 Reducer를 향하게도 할 수 있고 자기 자신의 Saga에게 다시 올 수도 있고, 자기 외의 다른 Saga에 보낼 수 있을 지도 모른다.

profile
👨🏻‍💻☕️ 🎹🎵 🐰🎶 🛫📷

0개의 댓글