[Redux] Redux의 기초 흐름

mokyoungg·2020년 10월 5일
3

Redux

목록 보기
3/7

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

공식 문서의 설명에 따르면...
Redux의 아키텍쳐는 엄격한 일방향 데이터 흐름을 따라 전개된다.
이는 어플리케이션 내의 모든 데이터가 같은 생명주기 패턴을 따르며, 앱의 로직을 좀 더 에측가능하게 하고 이해하기 쉽게 만든다는 뜻이다. 이는 또한 데이터 정규화를 도와서 같은 데이터의 복제본들이 서로를 모르고 여럿으로 나눠지지 않도록 해준다.

Redux의 기초 개념들이 어떻게 상호작용하는지 정리하였다.



1. Redux의 작동방식(흐름)

Action Creator > Action > dispatch > Reducer > State

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

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

2. Redux를 사용하기 위한 기초 세팅.

2-1. react-redux로 react와 redux를 연결한다.(src/index.js)

1
import React from "react";
import ReactDOM from "react-dom";
2
// react-redux에서 Provider를 가져온다.
import { Provider } from "react-redux";
// redux에서 createStore를 가져온다.
import { createStore } from "redux";
3
import App from "./components/App";
// combineReducer를 가져온다.
import reducers from "./reducers";
4
ReactDOM.render(
  <Provider store={createStore(reducers)}>
    <App />
  </Provider>,
  document.querySelector("#root")
);
  • ('#root')가 있는 최상위 레벨의 index.js에서 시작한다.
  • Provider를 통해 connect()가 있는 모든 컴포넌트를 store와 연결한다.
  • createStore의 인자로 reducers(comnbineReducers)를 넣는다.
  • redux의 store에 모든 reducer들이 할당되고 connect를 통해 컴포넌트에서 접근할 수 있게 된다.

2-2. reducer 작성(src/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 할당
  selectedNumber: selectNumberReducer, //selectNumber라는 키의 값으로 selectNumberReducer 할당
})
  • 순수한 reducer를 작성(2번)
  • action에 따라 previousState가 변하는 reducer를 작성(3번)
  • combineReducers를 redux에서 가져와(1번) 모든 reducer를 새로운 키와 값으로 할당한다.(4번)

2-3. action 작성(src/actions/index.js)

//action creator 선언
export const selectNumber = () => {
  return {
    //action 선언
    type: "SELECTED_NUMBER", //액션은 대문자와 스네이크 표기법을 사용.
    payload: 1, //액션이 전달하는 내용
  }
}
  • action creator를 선언하고 이것이 반환하는 action을 작성한다.
  • action의 type과 payload를 작성한다.


3. 컴포넌트에서 사용하기(src/components/예시컴포넌트.js)

1
import React from 'react'
// react-redux 라이브러리에서 connect를 가져옴
import { connect } from 'react-redux;
// action 폴더에서 selectNumber 가져오기
import { selectNumber } from '../actions'
2
class 예시컴포넌트 extends Component {
  render(){
    return(
    <div>
      <div>
       {this.props.numbers[0].number}
	  <div>
3
      <button onClick={()=>this.props.selectNumber()}>
        클릭하세요
      </button>
4
        <div>{this.props.selectedNumber}</div>
    </div>
    )
 } //컴포넌트 생성 코드 종료.
5
 // 컴포넌트 생성 코드의 외부에서 mapStateToProps 사용(store 에서 데이터 받아오기)
const mapStateToProps = (state) => {
  return {
    //받아올때 쓸 state의 이름' : state.'reducer에서 정한 데이터 이름' 
    numbers : state.numbers,
    selectedNumber: state.selectedNumber
  }
}
6
// connect()로 컴포넌트와 redux store 연결하기
// connect()의 첫번째 인자, mapStateToProps는 store에서 state를 받아온다.
export default connect(mapStateToProps, {selectNumber})(예시컴포넌트)

코드 설명

1번 > 5번 > 6번 > 2번 > 3번 > 4번 순서이다.

1번 코드

  • 컴포넌트를 redux의 store와 연결하는 connect() 함수를 가져온다.
  • 컴포넌트에서 사용할 action(selectNumber)을 가져온다.(이는 컴포넌트에서 이벤트가 발생한다는 뜻이다.)

5번 코드

  • mapStateToProps를 작성하여 store에 있는 모든 reducer(state와 연관된)를 가져올 준비를 한다.
  • console.log(state) 작성시, 모든 리듀서들이 나온다.
  • 2-2-4의 코드에서 작성된 combineReducers를 보면 numbers와 selectedNumber라는 키 값에 각각 리듀서를 할당하였다.
  • 이를 다시 컴포넌트에서 할당한다.
    -numbers(컴포넌트에서 사용할 key)
    -state.numbers(컴포넌트에서 사용할 값(value)이며 numbersReducer이다.)
  • 마찬가지로 selectedNumber라는 이름(key)으로 해당 리듀서를 값으로 가지고 왔다.
  • 컴포넌트에서 사용할 key 값은 props[key]의 형태로 리듀서(컴포넌트에서 새롭게 할당된 값)에 접근한다.

6번 코드

  • connect()로 컴포넌트와 redux store를 연결한다.
  • 5번에서 작성한 mapStateToProps를 connect()의 첫번째 인자로,
  • 1번에서 가져온 selectNumber를 두번째 인자로 둔다.
  • 이를 통해 예시 컴포넌트는 props로 액션과 리듀서들을 받을 수 있게 되었다.(클래스형 컴포넌트로 작성됨)

2번 코드

  • {this.props.number}는 2-2-2의 numbersReducer 이다.
  • {this.props.number[0].number}는 numbersReducer 배열의 0번째 인데스의 number라는 키의 값이다.
  • 따라서 0 이라는 값을 렌더한다.

3번 코드(컴포넌트에서 이벤트 발생, action creator 호출, action dispatch)

  • 버튼태그에 onClick 이벤트를 할당하여, 버튼 클릭시 selectNumber가 호출된다.
  • selectNumber는 액션 생성자로, action을 반환한다.(2-3의 type: 'SELECTED_NUMBER' 의 action)
  • action은 자동으로 dispatch 되는것처럼 보이나, 6번에서 작성한 connect()함수 덕분에 dispatch 된다.

4번 코드(reducer로 dispatch된 action때문에 state값 변화, 렌더)

  • {this.props.selectedNumber}는 2-2-3에서 작성된 selectNumberReducer이다.
  • 해당 리듀서는 최초의 state(selectNumber)의 값으로 null을 가진다.
  • 해당 리듀서는 들어오는 action의 type을 보고 state값(selectNumber)을 바꾼다.
  • dispatch된 action의 type은 'SELECTED_NUMBER'로, 해당 리듀서에서 작성한 가정문의 action type과 같다.
  • 따라서 그 액션의 payload 값을 반환한다.
  • 2-3에서 작성한 액션의 payload값은 1이다.
  • 따라서 1을 보여준다.


Redux의 흐름을 이해하기 위해 작성한 코드이며 완벽한 코드는 아니다.
아마 최초의 selectNumber의 값이 null이기에 에러가 발생할 수 있다.
2-2-2에서 작성한 리듀서를 활용한 map과 함께 사용하는 액션이나 액션의 인자를 넣어 사용하는 등의 코드는 아니다.
배열, 객체의 형태를 띈 리듀서가 액션을 통해 바뀌는 코드는 아니다.
api, axios, routing 등의 개념과 함께 쓰는 코드는 아니다.

이후 추가 예정이다.

profile
생경하다.

0개의 댓글