ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Redux] React-Redux
    Front-End(Web)/React - 라이브러리들 2021. 2. 16. 18:58
    반응형

    이전 포스팅에서 React+Redux 조합을 했듯이, Container 와 Presentational 기능분리의 번거로움이 있었다.

    아마, 이를 Context API의 Provider, Consumer 개념처럼 Global State를 공급하는 역할을 이 react-redux가 해줄 것 같다.


    💜 React? Redux? React-Redux?

    React는 자바스크립트 기반 SPA 라이브러리, Redux는 React 뿐만 아니라 JS환경의 상태관리를 개선하기 위해 등장한 라이브러리다.
    그렇다면, React 프로젝트 시 설치하는 Redux 말고, React-Redux 라이브러리의 의의는 무엇일까?

    - 의의

    Redux 자체는 React, Angular, Vue 및 vanila JS 를 포함한 모든 UI 레이어 또는 프레임워크와 함께 사용 가능한 독립형 라이브러리이다.

    모든 UI 프레임워크는 Redux를 사용하는 경우, UI 코드에서 'UI 바인딩 라이브러리' 를 사용하여 프레임워크와 Redux를 연결한다.

     

    React-Redux 는 React 공식 Redux 바인딩 라이브러리이다. React + Redux를 사용하는 경우, 두 라이브러리를 바인딩해야 한다.

    (출처: https://react-redux.js.org/introduction/why-use-react-redux )

     

    한마디로, react-redux는 react와 redux를 바인딩(연결) 해주는 라이브러리 인 것이다.

     

    - 설치

    npm install react-redux

    💜 React-Redux 주요 키워드

    react-redux 에서 추가적으로 다루는 개념(키워드)들이 있다. 이에 대해 간단하게 정리해보았다.

    위에서 언급했듯, React-Redux 가 제공하는 함수들은 대부분 React ~ Redux 간 연결기능을 주로 담당한다.

     

    1. Provider

    • Provider는 connect() 함수에 포장된 모든 컴포넌트가 Redux 스토어를 사용할 수 있게 해준다. (props로 스토어를 받음)
    • 이같은 특징으로, 앱 최상위 레벨에서 Provider를 렌더링한다.
    import React from "react";
    import ReactDOM from "react-dom";
    import { createStore } from "redux";
    import reducers from "./reducers";
    import { Provider } from "react-redux";	  // Provider는 react-redux 라이브러리에서 가져옴
    import App from "./components/App";
    
    ReactDOM.render(
      // Provider 사용예시
      <Provider store={createStore(reducers)}>
        <App />
      </Provider>,
      document.querySelector("#root")
    );

     

    2. connect()

    • connect() 함수는 React 컴포넌트를 Redux 스토어와 연결한다. 
    • connect() 된 컴포넌트는 스토어에서 상태를 받아오거나, 디스패치 전달을 할 수 있다.
    • connect() 문법: connect([mapStateToProps], [mapDispatchToProps])([전달할 컴포넌트명])
    import React from 'react'
    import { connect } from 'react-redux;   // connect 는 'react-redux' 라이브러리에서 가져옴
    class Example extends Component {
      render(){
        return(
        <>
         예시 컴포넌트의 내용
        </>
        )
     } 
    
    export default connect(null)(Example)

     

    3. mapStateToProps

    • connect() 함수의 첫 번째 인자로 전달된다.
    • 스토어 내부의 모든 state 값을 인자로 받으며, 컴포넌트가 필요로 하는 데이터 객체를 반환한다.
    • 연결된 컴포넌트에서 필요한 상태(state)를 선택하는데 사용된다. (= 상태 불러오기, getState)
    • store 상태가 바뀔 때마다 호출된다. (= 구독, subscribe)
    import React from 'react'
    import { connect } from 'react-redux;
    
    class Example extends Component {
      render(){
        return(
        <>
         예시 컴포넌트의 내용
        </>
        )
     }
    
    const mapStateToProps = (state) => {
      return {
        //받아올때 쓸 state의 이름' : state.'reducer에서 정한 데이터 이름' 
        needData : state.needData
      }
    }
    
    export default connect(mapStateToProps)(Example)

    mapStateToProps() 함수는 해당 컴포넌트에서 스토어의 상태를 받고자 할 때 사용된다. (useContext Hooks 적용과 유사)

    스토어의 state를 인자로 받아, 우리가 사용하고자 하는 객체형태로 재구성한다. 이 객체는, Example 컴포넌트의 props로 전달된다.

     

    4. mapDispatchToProps

    • connect() 함수의 두 번째 인자로 전달된다.
    • 스토어의 dispatch 함수를 인자로 받으며, 컴포넌트에 적용할 함수를 객체에 담아 전달한다.
    import React from 'react'
    import { connect } from 'react-redux;
    
    class Example extends Component {
      render(){
        return(
        <Example onClick={this.props.onClick}>
         예시 컴포넌트의 내용
        </Example>
        )
     }
    
    const mapDispatchToProps = (dispatch) => {
      return {
        //받아올때 쓸 props(함수명)의 이름' : dispatch(action) 함수
        onClick : () => {
          dispatch({
            type: 'INCREMENT',
            size: 2,
          })
        }
      }
    }
    
    export default connect(null, mapDispatchToProps)(Example)

    mapDispatchToProps 역시 객체를 반환하는데, 특징은 키가 props명, 키값은 우리가 활용할 디스패치 함수가 된다.


    💜 React-Redux 적용하기

    기존에 제작한 Container 컴포넌트들을 각각 React-Redux 를 통해 간소화하는 작업을 해보겠다.

    // AddNumberCon.js
    
    import React from 'react'
    import AddNumber from '../components/AddNumber';
    import store from '../Store';
    
    const AddNumberCon = () => {
      return (
        <AddNumber onClick={(size) => {
          store.dispatch({
            type: 'INCREMENT',
            size,
          })
        }}/>
      )
    }
    // ShowNumberCon.js
    
    import React, { useState } from 'react';
    import store from '../Store';
    import ShowNumber from '../components/ShowNumber';
    
    const ShowNumberCon = () => {
      const [number, setNumber] = useState(0);
      store.subscribe(() => {
        setNumber(store.getState().number)
      })
    
      return (
        <ShowNumber number={number} />
      )
    }

     

    - React-Redux 적용

    1. Provider 설정

    // index.js
    
    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    import { Provider } from 'react-redux'; 
    import store from './Store';
    import './index.css';
    import reportWebVitals from './reportWebVitals';
    
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>
      , document.getElementById('root')
    );
    
    reportWebVitals();

    앱 최상위에서 다음과 같이 <Provider>로 감싸준다. props는 스토어를 지정해주면 된다.

     

     

    2. Container 컴포넌트의 connect() 적용

     

    1) mapStateToProps : map + Redux-State + to + React-Props

    // ShowNumberCon.js
    
    import { connect } from 'react-redux';
    import ShowNumber from '../components/ShowNumber';
    
    const mapStateToProps = (state) => {
      return {
        number: state.number,
      }
    }
    
    export default connect(mapStateToProps)(ShowNumber);

    상태값을 활용하는 <ShowNumber> 컴포넌트의 경우, mapStateToProps 를 통해 스토어의 상태를 전달한다.

    스토어 상태 중, 우리가 필요한 number에 대해서만 재가공한 객체가 props로 전달된다.

     

    2) mapDispatchToProps : map + Redux-Dispatch + to + React-Props

    // AddNumberCon.js
    
    import { connect } from 'react-redux';
    import AddNumber from '../components/AddNumber';
    
    const mapDispatchToProps = (dispatch) => {
      return {
        onClick: (size) => {
          dispatch({
            type: 'INCREMENT',
            size,
          })
        }
      }
    }
    
    export default connect(null, mapDispatchToProps)(AddNumber);

    이벤트 핸들러로 디스패치를 활용하는 <AddNumber> 컴포넌트의 경우, mapDispatchToProps 를 통해 디스패치 함수를 전달한다.

    객체 형태로 props가 전달되며, 키는 props명, 키값은 dispatch(action) 함수가 들어간다.


    확실히 Context API 에 비해 러닝커브가 높다는 것이 느껴졌다. (useReducer 를 제외한 비교이기는 하나)

    무엇보다, Container 컴포넌트가 아직 존재한다는 것에 대해 의문이 들기도 한다. (mapStateToProps, mapDispatchToProps)

     

    또한, 생활코딩 강의는 클래스형 컴포넌트 위주로 이루어졌기에, 함수형에 관한 공부도 추가하면서 좀 더 원활하고 효율적으로 Redux를 활용할 수 있는 방법에 대해 고민해봐야겠다.

     

    [출처]

    - Redux 공식문서: react-redux.js.org/introduction/quick-start  

    - mokyungg 님의 블로그: velog.io/@mokyoungg/Redux-react-redux-react-redux

    반응형
Designed by Tistory.