-
connect 함수는 리액트 앱의 하위 컴포넌트에서 redux store를 접근하는 것을 가능하게 해주는 역할을 한다. 이 함수를 이용해서 컴포넌트 단에서 redux store에 접근하고 액션을 호출 할 수 있게 된다. 이번 포스트에서는 간단한 예제로 connect 함수를 통해 redux store를 사용하는 방법을 다뤄보려고 한다.
0. 준비작업
connect 함수 소개를 위해 예제와 텍스트와 숫자를 담당하는 redux를 만들었다.
BlogStore.js
import { createStore, combineReducers } from 'redux'; const textReducerState = { text: '', name: 'textReducer' }; const textReducer = (state = textReducerState, action) => { switch (action.type) { case 'SET_TEXT': return { ...state, text: action.text }; default: return state; } } const numberReducerState = { numberState: 30, name: 'numberReducer' }; const numberReducer = (state = numberReducerState, action) => { switch (action.type) { case 'SET_NUMBER': return { ...state, number: action.number }; default: return state; } }; export const configureStore = () => { const store = createStore( combineReducers({ text: textReducer, number: numberReducer }) ); return store; };
BlogActions.js
export const setText = ( text = '' ) => ({ type: 'SET_TEXT', text }); export const setNumber = ( number = 0 ) => ({ type: 'SET_NUMBER', number });
1. Provider
configureStore() 함수를 통해 store를 생성하고 Provider 태그에 store를 속성값으로 넣는다. 이러면 하위에 추가되는 component에서 redux store를 바라볼 수 있는 창구가 만들어진다.
import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import { configureStore } from './BlogStore'; import BlogMain from './BlogMain'; const store = configureStore(); const jsx = ( <Provider store={store}> <BlogMain /> </Provider> ); ReactDOM.render(jsx, document.getElementById('app'));
2. connect
하위 컴포넌트 단에서는 Provider에서 제공하는 store 함수를 connect 함수를 통해서 받아온다. 함수 형식이든 클래스 형식이든 받는 방식은 동일하다.
2.1 클래스형식
import React from 'react'; import { connect } from 'react-redux'; import BlogDetail from './BlogDetail'; class BlogMain extends React.Component { render() { console.log(this.props.text) console.log(this.props.number) return ( <div> <p>BlogMain component</p> <BlogDetail /> </div> ) }; }; const mapStateToProps = (state) => { return { text: state.text, number: state.number } }; export default connect(mapStateToProps)(BlogMain);
클래스 형식 컴포넌트를 export 할 때 connect 함수를 사용하고 첫번째 인자에 mapStateToProps 함수를 넣었는데 redux store에 있는 값을 컴포넌트에 어떻게 넘겨줄지 세팅하는 작업이다. 넘겨 받은 값은 component의 props에 들어가서 호출 할 수 있다. 아래 사진은 render() 함수 안에서 console로 찍은 로그다. textReducer와 numberReducer가 출력되는 것을 볼 수 있다.
2.2 함수 형식
import React from 'react'; import { connect } from 'react-redux'; const BlogDetail = (props) => ( <div> <p>BlogTextDetail</p> <p>{props.text.name}</p> </div> ); const mapStateToProps = (state) => { return { text: state.text }; }; export default connect(mapStateToProps)(BlogDetail)
함수 형식도 크게 다르지 않다. 컴포넌트 내에서 호출 할 때 this를 부르지 않아도 된다는 점만 다르다. 위 코드로 호출하면 아래 그림처럼 화면 뷰가 그려진다.
3. Action
connect로 컴포넌트에 전달 할 때 store만 전달 하는것이 아니라 action을 넣을 수 있는 dispatch 함수까지 전달된다. react 디바이스 툴을 사용해보면 component의 props 안에 dispatch가 들어있는 것을 확인 할 수 있다.
실제로도 잘 사용할 수 있을 지 테스트 해보자. 방금 전에 사용한 BlogDetail 컴포넌트를 살짝 수정해서 현재 store에 저장된 text를 출력하고 버튼을 추가하고 클릭하면 text를 BlogDetail로 바뀌도록 했다.
import React from 'react'; import { connect } from 'react-redux'; import { setText } from './BlogActions'; const BlogDetail = (props) => ( <div> <p>BlogTextDetail</p> <p>current store text value: {props.text.text}</p> <button onClick={() => { props.dispatch(setText('BlogDetail')) }}>Change text to BlogDetail</button> </div> ); const mapStateToProps = (state) => { return { text: state.text}; }; export default connect(mapStateToProps)(BlogDetail)
함수를 실행하고 버튼을 클릭하니 화면이 아래와 같이 store의 text 값이 BlogDetail로 변경됐다.
4. 총평
코딩을 처음 하는 분이면 이걸 왜 이렇게까지 해야할지 이해가 안될 수 있을 것 같은데 이전에 mvvm, mvc 패턴을 경험해본 개발자들에게는 redux가 크게 어려울 것 같지 않다. 강의 들을 때는 헷갈렸는데 실제로 코드로 짜보니까 어떤 식으로 구조를 잡아야할 지 느낌이 온다. 물론 자바스크립트 언어 특성상 state 세부 이름을 관리할 때 꽤 귀찮음을 겪을 것 같긴 하다.