[+51]typescript에서 React-Redux 사용하기

AeRi Lee·2020년 3월 18일
0
post-thumbnail

Redux는 무엇인가?

Redux는 application 전체의 상태(state)관리하기 위한 library이다.

Redux는 왜쓰는가?

React는 부모 컴포넌트에서 자식 컴포넌트에 props로 data나 state 변화를 넘겨주기 쉬운데 멀리멀리 돌아서 state값을 바꿔줘야 하고 그게 페이지도 많고 규모가 점점 커진다면 관리하기도, 개발하기도 복잡해진다.

그 복잡함을 store라는 곳에서 state를 관리함으로써 편하게 만들어준다.


React-Redux

Create React App (CRA)에서 개발을 했기 때문에 나는 react-redux를 사용하였다. react-redux은 redux를 react에서 사용하기 좋도록 만들어진 것이다.

원래 state의 변화를 감지하거나, action을 발행하려면 store.dispatch(), store.subscribe() 등의 메서드를 매번 사용해야 하는데, react-redux로 component에서 store를 쉽게 읽고, action을 쉽게 dispatch할 수 있도록 해준다.

1.설치

이를 사용하기 위해서 우리는 redux도 설치해야 하고 react-redux도 설치해야 하는데 한번에 설치할 수도 있다.
npm install --save redux react-redux

2.store 사용하기 위한 첫 설정(store만들기)

redux는 createStore라는 함수로 store를 생성한다.
보통 store는 app에 오직 하나만 있다. 이 유일한 store에서 app 전체의 상태를 관리한다.
store 파일을 따로 만들어줘도 되지만 나는 store의 createStore은 index파일에서 해줬다.
redux의 createStore함수에 reducer를 인자로 주어야 한다. combineReducer를 해줄 rootReducer를 인자로 넣기로했다.
react app에서 store를 사용하려면 <Provider> 를 사용해야 한다. 가장 최상위 컴포넌트를 Provider로 래핑하고 속성에 store를 전달한다.

이렇게 하면 파일마다 store를 import해주지 않아도 전역으로 쓰일 수 있어서 편리하다.

3.Action

Action은 사용자의 입력이나 UI 조작, 웹 요청 완료같이 어떠한 상태 변화를 일으킬 수 있는 현상이다. 즉, 어떤 조작인지 정보를 갖고 있는 자바스크립트 객체이다. 조작 정보는 type 프로퍼티에 지정한다.

action 객체를 return 해주는 액션 생성 함수는 이렇게 생겼다.

  • actionplain object이다.
  • action은 반드시 type 프로퍼티(=타입 이름)를 가져야만 한다.
  • action은 payload를 가질 수도 있다.
    payload는 특정 액션에 부가적인 데이터를 전달하고 싶을 때 사용한다. 물론 payload가 아닌 다른 다른 프로퍼티명을 사용해도 된다.
    action의 type은 reducer에서도 사용해야되기 때문에 상수로 관리하자.

보통 action은 객체 리터럴로 바로 정의하는 것이 아니라 Action Creator(액션 생성자) 함수(여기서는 songList 함수 )로 action을 생성한다. 동일한 구조의 action 객체를 만들기 위함이다. Action Creator로 만들지 않으면 action 객체 구조가 일정하지 않을 수도 있기 때문이다.

그리고 여기에서 주의해야 할 점!!!
띄어쓰기 때문에 에러가 날 수도 있다. ( item 이 아닌 (item으로 적는 것을 추천.

4.reducer생성

store를 생성하려면 reducer가 필요하다.
reducer는 store가 가지고 있는 state를 변화시키기 위한 함수이다. reducer는 이전의 state와 action을 인자로 받고, 이 action의 내용(type)에 따라 state를 변화시킨다.
일단 reducer를 정의해보자. 아래는 songList이라는 reducer를 정의한 것이다.
그리고 위에 기존 state에 담겨있을 initialState를 적어준다. 이름은 마음대로 적어도 된다. function songList의 인자에서 state= 내가 정한 이름 을 해주면 된다.

각 action type 별로 새로운(next) state를 생성하여 return하면 된다.

ADD_MUSIC 이라는 action type과, REMOVE_MUSIC 이라는 action 등 type에 따라 return하는 state가 다르다. ADD_MUSIC은 테마에 담긴 음악을 재생목록에 추가해주는 역할을 하고 지우는 것은 삭제 버튼을 누르면 한개가 삭제되게 하는 것이다.

내 코드에는 state의 초기상태가 있었지만 state초기상태가 없다면 state를 null로 지정해주면 된다.

5.combineReducers

combineReducers 헬퍼 함수는 서로 다른 리듀싱 함수들을 값으로 가지는 객체를 받아서 createStore에 넘길 수 있는 하나의 리듀싱 함수로 바꿔준다.

생성된 리듀서는 내부의 모든 리듀서들을 호출하고 결과를 모아서 하나의 상태 객체로 바꿔준다. 상태 객체의 형태는 reducers로 전달된 키들을 따른다.

하지만 내가 실제로 사용했던 리덕스는 리듀서 함수가 하나였기에 이렇게 작성했다.

RootReducer


6.connect

connect에서는 ()() 이렇게 소괄호가 두번 들어가는데 이 의미는
connect()라는 함수가 return이 되고 그 값에 또 ()함수를 돌려서 나온 값을 export하겠다는 것이다.
근데 그 값이 wrapping된 값이 나올 것이라는 의미이다.

다른 예제로 connect역할을 슬쩍 보자면,,

react-redux를 쓰지 않았을 때 사용됐을 색칠된 부분을 connect()()가 마법을 부려서 해준다!


connect의 첫 번째 소괄호에서 인자 2개가 올 수 있는데 첫 번째 인자로 mapStateToProps가 오고 두 번째 인자로는 mapDispatchToProps가 온다. 즉, connect에는 인자가 2개가 올 수 있다.
인자를 안 줄수도 있는데, 준다면


이렇게 넘긴다.
두 번째 인자가 없다면 첫 번째 인자만 써주면 되지만 첫 번째 인자는 없는데 두 번째 인자는 있다면 첫 번째에 null을 써줘야 한다. 그렇지 않으면 나는 두 번째 인자를 첫 번째 인자로 인식하기 때문이다.

함수이름은 마음대로 해도 된다.
근데 이게 redux도 props를 가지고 react도 props를 가지니까 헷갈린다.
그러니까 이름을 이해하기 쉽게 적고자 한다면

mapReduxStateToReactProps(connect의 첫 번째 인자) => Redux의 state를 react에게 props로 mapping(연결)해준다는 의미로 이름을 지어준다.
mapReduxDispatchToReactProps(connect의 두 번째 인자) => Redux의 dispatch를 react의 props로 mapping(연결)해준다는 의미로 이름을 지어준다.

이렇게 정하자.


그럼 connect를 어떻게 쓰느냐.

클릭해서 재생목록에 더하기 기능 리덕스(클릭하는 쪽)

클릭 이벤트를 받아서 state을 바꿔줄 파일 상단부분

  • connect랑 함수 import 하기

    중간 부분
  • onClick에 함수 실행. 이때 무엇인가를 전달할 때는 this.getMusic 이렇게 쓰는 것이아니라 사진 처럼 ()=>this.getMusic(보낼 것) 이렇게 쓰도록 한다.
  • getMusic에서 여기에 해당하는 테마의 노래들을 fetch해서 state에 저장하고 보내지 않고 바로 보내준다.


하단부분

  • action함수를 인자로 보내준다. redux의 state를 받는 것은 노래가 추가될 공간이니 여기가 아니므로 null을 적어주자.

리스트 추가되는 페이지(받는 쪽)

상단부분

  • connect만 import

    중간부분
  • songList가 state변화된 새 배열이다.
    songList를 map을 돌려서 재생 목록에 다 뜨게 했다.

    하단부분
  • redux의 새 state를 props로 보내줘서 현재 받을 파일에서 쓸 수 있게 가지고 온다.
  • connect에서 첫 번째 인자는 현재 하고 있는 기능.즉 재생목록에 여러개 노래를 더하는 것과 관련된 인자를 넣어줬고 setNewList는 다른 기능이다.

removeMusic 기능 리덕스

상단부분

  • 마찬가지로 connect와 removeMusic이라는 action 함수를 import

중간 부분

  • 이 페이지는 hooks를 이용한 함수형으로 제작되었기 때문에 this 없이 props.removeMusic으로 써야 했다.
  • 삭제 버튼에 삭제한 음악의 id를 넘긴다.

하단부분

  • state를 반영하는 것이 아니라 remove해서 state를새로 만들것이기 때문에 첫 번째 인자는 null!
  • 이 함수를 통해 음악이 삭제되면 바뀐 songList가 다시 들어갈 것이다.

connect 다시 정리하자면

connect라는 api는 2번 호출이 되어야 하는데
첫번째 인자는 redux의 store의 state를 react의 props로 전달해주고
두번째 인자는 redux의 dispatch를 react 컴포넌트의 props로 전달해주는
역할을 우리 대신에 해준다는 것이죠.

그러나 우리가 react redux를 사용할 때 고통스러운 것은 그 마법 때문이다.


이 부부은 추후에 더 공부할 것

  1. 위의 action을 Action Creator로 만든다면 아래와 같다. 이라는 이름으로 만들었다.
const addMusic = options => ({
  type: 'ADD_MUSIC',
  payload: { options }
});
addMusic({
  title: '힙 터질 때',
  dim: true
});
  1. action의 발행과 state 변화 감지

원래 action을 dispatch(발행)하고 싶다면 store.dispatch() 메서드를 사용한다. react-redux에서는 사용이 조금 다르다.
더 공부해야 할 것 2 이다.


참고

google에 react-redux를 검색하면 공식 홈페이지가 나온다.
거기에 why use react-redux? 칸이 있는데 여기 클릭해서 밑으로 내려가면
connect.js Explained가 있다.

클릭해서 들어가면 redux를 만든 분이 react-redux의 초창기 코드가 들어있다.
다 들어있다.
내부적으로 함수값. return값이 함수값.
또 실행. component를 return 하게 되는 것이다.
인자로 전달될 때 wrappedcomponent 안에 넣어서 render가 된다.

또, unit props로 unit옮기고 했던거 마법같이 자동으로 보내준다.
그 원리는 초창기 코드에서 {...this.props}부분이다.


profile
👩🏻‍💻 Junior Web Frontend Developer

0개의 댓글