[Redux] Redux의 기초 개념

mokyoungg·2020년 10월 5일
2

Redux

목록 보기
2/7

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

Redux는 React 대신에 state를 관리해주는 라이브러리이다.
컴포넌트가 많아지고 깊어졌을 때 불편한 점을 해결하기 위해 사용한다.

redux는 react 컴포넌트 외부에서 자유롭게 움직이는 컨테이너라고 생각해야 한다.
actoin, reducer 등의 redux의 개념을 컴포넌트에서 사용하기 위해선 props로 받아와야 한다.

props라는 것을 부모 컴포넌트의 state 값을 받아올 때 사용하는 것처럼
redux의 state를 props로 받아온다고 생각하자.

redux는 컴포넌트와 부모자식 사이가 아니라 하늘에 떠 다니는? 그런 존재라고 생각해야한다.



1. Redux의 작동방식

redux는 다음과 같이 작동한다.

Action Creator > Action > dispatch > Reducer > State

이를 이해하기 위해선 react와 redux를 쓴 react의 렌더링 과정의 차이를 아는게 도움이 된다.

React 렌더링 과정.

  • component 내에 이벤트 호출(클릭, 입력 등)
  • 이벤트와 연결 된 setState 또는 useState 호출
  • state 값 변화
  • 렌더링

Redux를 사용한 React의 렌더링 과정

  • component 내에 이벤트 호출(클릭, 입력 등)
  • 이벤트와 연결된 action creator 호출
  • action creator가 생성한 action 호출
  • action이 reducer로 전달(dispatch)
  • dispatch된 action의 영향으로 reducer의 state값이 변화
  • 렌더링

state 값의 변화로 렌더링이 일어난다는 점은 똑같다.
state의 변화가 컴포넌트 내부에서 일어나는지, redux의 store에서 일어나는지의 차이다.
redux는 state의 값을 컴포넌트 외부에서 대신 관리해주는 대행사라고 생각하면 될 것 같다.

음...부모님(부모컴포넌트)한테서 용돈(state)을 내가(자식 컴포넌트) 직접 받는(props) 것이 아니라
부모님(컴포넌트)이 용돈(state)을, 은행계좌를(redux store) 통해 전달하고(dispatch) 내가(컴포넌트) 이후에 받는다(props)?

이게 더 이해하기 어렵나.. 부모컴포넌트>자식컴포넌트가 아니라 컴포넌트>리덕스>컴포넌트로 state 값을 주고 받는다.



2. Store

2-1. Store

  • 앱의 전체 상태 트리를 가지고 있는 저장소이다.(state의 총집합)
  • 이 안의 상태를 바꾸는 유일한 방법은 여기에 action을 보내는 것 뿐이다.
  • store는 클래스가 아니며 단지 몇가지의 메서드가 들어있는 객체일 뿐이다.
  • 생성하기 위해서는 루트 리듀싱 함수를 createStore에 전달하면 된다.

2-2. createStore

  • 앱의 전체 상태 트리를 보관하는 Redux store를 만든다.
  • 앱 내에는 단 하나의 store만 있어야한다.

2-3. Store 예시 코드(/scr/index.js)

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
// redux 라이브러리에서 createStore를 가져온다.
import { createStore } from "redux";
import App from "./components/App";
//createStore의 인자로 사용할 reducer를 가져온다.
import reducers from "./reducers";
ReactDOM.render(
// Provider 태그 안에 app의 store을 만들고 reducer를 넣는다.
  <Provider store={createStore(reducers)}>
    <App />
  </Provider>,
  document.querySelector("#root")
);
  • react-redux의 provider로 react 컴포넌트와 redux의 store를 연결한다.
  • redux의 store에 App의 reducer를 할당한다.
  • 이후 connect()가 있는 모든 컴포넌트는 store에 접근이 가능하다.

store.. reducer.. 헷갈린다.
redux의 store에 reducer의 내용을 채우는것인가!
store를 만들고 나면 이제 똑같은 말 아닌가!



3. Action

3-1. action

  • 액션은 컴포넌트에서 데이터를 store로 전달한다.
  • 액션의 유형을 나타내는 'type'이 있어야 한다.(필수)
  • type의 값은 대문자로 작성하고 띄어쓰기는 스네이크 표기법 처럼 _(underScore)를 붙인다.(국룰)
  • 액션의 내용(데이터)을 나타내는 'payload'를 작성한다.(반드시는 아니지만 국룰이다.)

3-2. action creator

  • 액션 생성자는 단순히 액션을 반환하는 개념이다.

3-3. action 예시 코드 1(src/actions/index.js), 액션 만들기

//action creator 선언
export const selectNumber = () => {
  return {
    //action 선언
    type: "SELECTED_NUMBER", //액션은 대문자와 스네이크 표기법을 사용.
    payload: 1, //액션이 전달하는 내용
  }
}

3-3. action 예시 코드 2(src/component/index.js), 액션 사용하기

1.
import React from "react";
import { connect } from "react-redux";
2.
// 액션생성자 가져오기(index.js 파일이라 이렇게 작성해도 된다.)
import { selectNumber } from "../actions";
3.
class 예시컴포넌트 extends Component {
  render(){
    return(
      <div>
  	//props로 액션생성자(selectNumber)을 받아옴
        //클릭시, 액션이 dispatch되어 reducer로 감
        <button onClick={()=> this.props.selcectNumber()}>
          select
        </button>
      </div>
    )
  }
}
4.
//mapStateToProps가 없어서 connect()의 첫번째 인자를 null로 처리
//connect()의 두번째 인자로 액션생성자(selectNumber)를 전달
export default connect(null, { selectNumber })(예시컴포넌트)

컴포넌트에서 액션을 사용하려면

  • 1>2>3>4의 순서대로 코드를 읽으면 이해하기가 좀 어렵다.
  • 1>2>4>3의 순서대로 코드를 작성하고 읽는것이 편하다.
  • 액션생성자를 컴포넌트에 가져오고, 이를 connect()함수에 전달한다.
  • 이제 액션 생성자는 redux에 존재하며
  • 이를 props로 받아 컴포넌트에선 사용한다.

공식 홈페이지의 번역은 위와 같은데 솔직히 이게 무슨 말이진 진짜 이해 안된다.
컴포넌트에서의 이벤트(클릭, 입력)를 통해 액션은 store로 전달(dispatch)가 되며
이후 store에 있는 state값을 변화시키는 것으로 보아...

action(creator) + dispatch를 useState 또는 setState의 개념으로 보아도 될 것 같다.



4. Reducer

4-1. reducer

  • 액션을 통해 어플리케이션의 상태(state)가 어떻게 바뀌는지 작성한 코드.
  • 이전 상태(previousState)와 액션을 받아 상태를 변화, 반환시키는 순수 함수이다.
  • redux에서 어플리케이션의 모든 상태(state)는 객체에 저장된다.

4-2. combineReducers(reducers)

  • 서로 다른 리듀서들을 값으로 가지는 객체를 받아 createSotre에 넘길 하나의 리듀서 함수로 바꿔준다.
  • 생성된 리듀서는 내부의 모든 리듀서들을 호출하고 결과를 모아 하나의 객체로 바꾼다.

4-3. reducer와 combineReducers 예시 코드(/scr/reducers/index.js)

1
//redux에서 combineReducers를 가져온다.
import { combineReducers } from 'redux'
2
//reducer 선언1(만들기)
const numbersReducer = () => {
  return [
    {number: 0},
    {number: 1},
    {number: 2},
    {number: 3},
  ]
}
3
//reducer 선언2(액션에 영향을 받는 리듀서)
//reducer(previousState, action)의 형태
//최초의 state 값은 없고 action을 받는다.
const selectNumberReducer = (selectNumber = null, action) => {
  if(action.type === 'SELECTED_NUMBER){
  	return action.payload
  }
  return selectNumber
}
4
//combineReducers로 reducer들 합치기
export default combineReducers({
  numbers: numbersReducer, //numbers라는 키의 값으로 numbersReducer 할당
  selectNumber: selectNumberReducer, //selectNumber라는 키의 값으로 selectNumberReducer 할당
})

combineReducers사용(1번과 4번)

  • 1번, redux에서 combineReducers를 가져온다.
  • 4번, reducer 들을 combineReducers로 합친다.
  • 리듀서를 numbers와 selectNumber의 키 값에 각각 할당한다.
  • 이후 connect() 된 컴포넌트에서, console.log(state.numbers)를 작성하면 numbersReducer가 반환하는 값들을 볼 수 있다.
  • 마찬가지로 connect() 된 컴포넌트에서, console.log(state.selectNumber)를 작성하면 selectNumberReducer가 반환하는 값들을 볼 수 있다.

Reducer 사용(2번과 3번)

  • 3번, action을 받고 type을 비교하여 해당 액션이 맞으면 액션의 payload 값으로 state값을 바꾼다
  • action의 type을 비교, 액션값이 다르면 기존의 state(previousState) 값을 반환

4-4. combineReducers 예시코드(/src/index.js)

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import App from "./components/App";
// reducers를 가져온다.(이는 combineReducers 이다.)
// 즉 모든 reducer들의 집합이다.
import reducers from "./reducers";
ReactDOM.render(
  //가져온 리듀서를 createStore의 인자로 넣는다.
  //connect()가 된 모든 컴포넌트에서 reducer에 접근할 수 있다.
  <Provider store={createStore(reducers)}>
    <App />
  </Provider>,
  document.querySelector("#root")
);


reducer 함수는 액션을 받아 상태를 반환하는 순수함수이다.
이와 관련된 API 호출이나 라우팅과의 연계. 그리고
기존의 state(previousState)의 값이 배열이나 객체의 형태일때의 변화 등의 내용은 다루지 않았다.

더 알아보기
https://ko.redux.js.org/basics/reducers

profile
생경하다.

0개의 댓글