[Redux] react? redux? react-redux?

mokyoungg·2020년 10월 5일
6

Redux

목록 보기
1/7

출처는 redux 공식문서입니다.
https://ko.redux.js.org/

react를 잘 쓰려면 redux를 알아야 한다.
그러나 redux는 어렵다. 왜 어려울까.

  • redux의 작동 방식을 이해하는 것이 어렵다.
  • redux와 관련된 새로운 개념이나 지식이 익숙하지 않다.

개인적으로 2번의 문제가 redux 공부를 방해하였다.
새로운 단어, 개념 등이 한꺼번에 쏟아져 나와 정신을 못 차렸다.
이를 정리하기 위해 글을 쓴다.

redux 개념에 앞서 redux와 react를 연결해주는 react-redux의 개념을 먼저 아는 것이 도움이 된다.


1. React? Redux? React-Redux?

처음 Redux를 알게 된 뒤 내가 가진 가장 큰 오해는 redux가 react의 아쉬운 점을 보완해주기 위해 탄생한 라이브러리라고 이해했다는 것이다. 물론, redux는 react를 보완해주는 측면은 있지만 react와 redux는 전혀 다른(연관이 없는) 라이브러리이다.
Redux는 자바스크립트 앱을 위해 탄생하였다.(React 때문이 아니다.)

Redux는 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너
출처 : https://ko.redux.js.org/

그리고 react에서 redux를 사용하려면 redux도 설치하고 react-redux도 설치해야한다.
라이브러리를 2개나 설치하는 만큼, 라이브러리에서 파생되는 개념들도 2배다.
(위에서도 이야기했지만 그래서 엄청 헷갈린다.)
redux는 상태 관리를 쓰는거라면 react-redux는 무엇인가?

1-1. react-redux

React는 SPA를 만들기 위해 사용된다.
Ract는 자체적으로 state(와 props)를 관리할 수 있지만 컴포넌트가 많아지고 깊어지면 state의 값을 관리하기가 피곤하다.
redux는 state를 편하게 관리하기 위한 목적으로 사용된다.
그렇다면 react-redux는 왜 쓰는가?

Why Use React Redux?
Redux 자체는 React, Angular, Vue, Ember 및 vanilla JS를 포함한 모든 UI 레이어 또는 프레임워크와 함께
사용할 수 있는 독립형 라이브러리이다. Redux와 React는 일반적으로 함께 사용되지만 서로 독립적입니다.
모든 종류의 UI 프레임 워크와 함께 Redux를 사용하는 경우 일반적으로 UI 코드에서 'UI 바인딩' 라이브러리를 사용하여
Redux를 UI 프레임 워크와 연결합니다. React Redux는 React용 공식 Redux UI 바인딩 라이브러리입니다.
Redux와 React를 함께 사용하는 경우 React Redux를 사용하여 이 두 라이브러리를 바인딩해야합니다.

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

한마디로, react-redux는 react와 redux를 연결해주는 라이브러리이다.



2. React-Redux에서 나오는 개념

react-redux가 제공하는 함수는 대부분 연결하는 기능을 제공한다.

2-1. Provider

  • Provider는 connect() 함수에 포장 된 모든 컴포넌트가 Redux Store를 사용할 수 있게 한다.
  • 그렇기 때문에 대부분의 어플리케이션은 전체 앱의 최상위 레벨에서 Provider를 렌더링한다.
  • Provider의 Props로는 store가 있으며, 이는 어플리케이션의 Redux Store이다.

Provier 사용의 예시(/src/index.js)

import React from "react";
import ReactDOM from "react-dom";
// Provider는 react-redux 라이브러리에서 가져온다.
import { Provider } from "react-redux";
// createStore는 redux에서 가져온다.
import { createStore } from "redux";
import App from "./components/App";
import reducers from "./reducers";
ReactDOM.render(
// connect()함수에 포함된 모든 컴포넌트가 redux store를 사용할 수 있기 위해,
// Provider는 최상위 레벨에서 렌더링 된다
// provider의 props로 store가 있으며 redux store를 할당한다.
  <Provider store={createStore(reducers)}>
    <App />
  </Provider>,
  document.querySelector("#root")
);

Provider는 최상위 레벨('#root'가 있는 index.js)에서 App.js 컴포넌트를 감싼다.
이를 통해 connect()가 포함된 모든 컴포넌트가 redux store를 사용할 수 있게 된다.

2-2. connect()

  • connect() 함수는 React 컴포넌트를 Redux Store에 연결한다.
  • connect()로 연결한 컴포넌트는 필요한 데이터(state)를 store에서 받아온다.
  • connect()를 통해 컴포넌트의 이벤트로 호출 된 action을 store로 보낼 수 있다.(dispatch)

connect() 함수 사용의 예시(/src/components/예시컴포넌트.js)

import React from 'react'
// react-redux 라이브러리에서 connect를 가져옴
import { connect } from 'react-redux;
class 예시컴포넌트 extends Component {
  render(){
    return(
    <>
      <div>
       예시 컴포넌트의 내용
	  <div>
    </>
    )
 } 
// connect()로 컴포넌트와 redux store 연결하기
export default connect(null)(예시컴포넌트)

정리하자면
1. connect() 함수를 'react-redux' 라이브러리에서 가져온다.
2. 'export default connect()(예시컴포넌트)' 형태로 컴포넌트를 connect()함수로 연결한다.
3. (connect()의 첫번째 인자로 mapStateToProps, 두번째 인자로는 reducer에 전달할 action을 넣는다.)

보기엔 어색하지만,
function connect()()는 유효한 자바스크립트 코드이다.

function connect(){
  return function(){
    return '안녕'
  }
}
connect()() // '안녕'

2-3.mapStateToProps

  • connect() 함수의 첫번째 인자로 전달된다.
  • store 내부의 모든 state값을 받으며, 컴포넌트가 필요로 하는 데이터를 객체를 반환한다.
  • 연결된 컴포넌트에서 필요한 데이터(state)를 선택하는데 사용된다.
  • store의 상태가 바뀔 때마다 호출된다.

mapStateToProps 예시(/src/components/예시컴포넌트.js)

import React from 'react'
// react-redux 라이브러리에서 connect를 가져옴
import { connect } from 'react-redux;
class 예시컴포넌트 extends Component {
  render(){
    return(
    <>
      <div>
       예시 컴포넌트의 내용
	  <div>
    </>
    )
 } //컴포넌트 생성 코드 종료.
 // 컴포넌트 생성 코드의 외부에서 mapStateToProps 사용(store 에서 데이터 받아오기)
const mapStateToProps = (state) => {
  return {
    //받아올때 쓸 state의 이름' : state.'reducer에서 정한 데이터 이름' 
    needData : state.needData
  }
}
// connect()로 컴포넌트와 redux store 연결하기
// connect()의 첫번째 인자, mapStateToProps는 store에서 state를 받아온다.
export default connect(mapStateToProps)(예시컴포넌트)
  • connect() 처리 된 컴포넌트는 연결만 한다.
  • store에 접근하여 state 값을 받아오기 위해선 mapStateToProps를 사용해야한다.
  const mapStateToProps = (state) => {
    console.log(state) // store에 있는 모든 state가 console에 보임
  }
 const mapStateToProps = (state) => {
   return {
     //사용자지정 이름(키) : store에서 사용자가 원하는 부분(값)
     조던 : state.조던 // 전체 state 중, '조던'이라는 키의 값을 '조던'에 할당함. 
 }

store에 있는 특정 키의 값을 원하는 이름에 할당하고, 객체의 형태로 반환한다.
mapStateToProps는 컴포넌트에서 필요한 state를 store에서 가져와 객체의 형태로 만들어준다.
이제 해당 컴포넌트에서 console.log(props)를 찍어보면 {조던 : 할당 된 값} 의 형태가 뜬다.
부모 컴포넌트가 아닌 store에서 state를 props로 받아오게 된다.



3. connect()와 mapStateToProps의 코드 예시 (/src/components/예시컴포넌트.js)

import React from "react";
// connect는 react-redux 라이브러리에서 가져온다.
import { connect } from "react-redux";
import { action#1 } from "../actions";
// 1-1. Component 생성 코드(함수형 컴포넌트로 state값과 action#1을 받아온다.)
const 예시컴포넌트 = ({needData, aciont#1}) => {
  return(
    <div>
      <button onClick={()=> {action#1}>  //클릭시, action을 reducer로 보내기
        액션 보내기!
      </button>
      <div>
        {needData} //store에서 받은 데이터
      </div>
    </div>
  )
}  //이 부분에서 컴포넌트 생성 코드는 끝난다.
// 1-2. Component 생성 코드(클래스형 컴포넌트)
class 예시컴포넌트 extends Component {
  render(){
    return(
      <div>
        <button onClick={()=>this.props.action#1}  //클릭시, action을 reducer로 보내기
        액션보내기!
        </button>
	<div>
          {this.props.needData} //store에서 받은 데이터
        </div>
      </div>
    )
 } //이 부분에서 컴포넌트 생성 코드는 끝난다.
// 컴포넌트 생성 코드의 외부에서
// mapStateToProps 사용(store 에서 데이터 받아오기)
const mapStateToProps = (state) => {
  return {
    //받아올때 쓸 state의 이름' : state.'reducer에서 정한 데이터 이름' 
    needData : state.needData
  }
}
// connect()로 컴포넌트와 redux store 연결하기
// connect()의 첫번째 인자, mapStateToProps는 store에서 state를 받아오고
// connect()의 두번째 인자, {action#1}는 store에 action#1을 보낸다.(dispatch) 
export default connect(mapStateToProps, { action#1 })(예시컴포넌트)

코드 추가 설명

  • connect() 함수로 컴포넌트를 redux의 store와 연결하였다.
  • connect() 함수의 인자는 mapStateToProps와 dispatch하고 싶은 action이다.
  • state(props)는 부모 컴포넌트에서 오는 것이 아닌 redux의 store에서 온다.
  • mapStateToProps를 통해 store의 state를 받으며, 원하는 이름으로 지정할 수 있다.
  • 함수의 코드는 위에서 아래로 읽어야하지만 이런 코드는 mapStateToProps부터 읽는 것이 좋다.

connect()함수로 컴포넌트를 연결하였다면..
클래스형 컴포넌트 : 컴포넌트 생성 코드에서 console.log(this.props)
함수형 컴포넌트 : 컴포넌트 생성 코드에서 console.log(props)
mapStateToProps 코드에선 console.log(state),로 확인해보는 것이 좋다.

정리하자면..

  1. Redux의 스토어와 connect() 함수의 연결
  2. mapStateToProps로 Redux store에 있는 모든 state 값들을 가져옴.
  3. mapStateToProps의 return 값으로 모든 state 중 필요한 state만 가져옴.
  4. 가져온 state 값들을 컴포넌트에서 props로 받아 사용한다.
  5. 받은 props는 mapStateToProps에서 지정한 이름으로 데이터를 보여준다.
    예시. console.log(props) // needData(지정한 이름) : {reducer에 저장된 state 값들}


react-redux의 모든 개념을 담은 글은 아니다.
내가 써보고 이해한 만큼만 작성하였다.

profile
생경하다.

1개의 댓글

comment-user-thumbnail
2021년 10월 15일

감사합니다.

답글 달기