Web/React

React - Redux & Middleware

또롱또 2022. 5. 27. 11:08
728x90

내가쓴 부분은 1도 없고, 스파르타 항해99에서 제공해준 정보이다.

왜 Redux를 쓰는가?

  • useState가 불편하기 때문이다.
    • 여러 컴포넌트에서 같은 state를 공유해서 쓰려면 부모 자식 컴포넌트를 반드시 거쳐야 하는데, Redux를 사용해서 state를 중앙에서 관리하면 원하는 컴포넌트에서 바로 가져와서 사용 할 수 있다.
  • 개발을 하면서 사용할 수 있는 devtools의 퀄리티가 좋고, 많은 개발자들이 사용하는 라이브러리라서 자료가 많아 error 해결이 용이하다.

리덕스 모듈 용어 정리


Action type

  • 어떤 행동을 의미한다. 여기서 행동이란, 가령 계산기 기능을 구현한다면 plus, minus 처럼 기능에 필요한 행동을 뜻한다.
  • action type은 object = {} 다. 그리고 무조건 type 이라는 key값을 가져야 한다.
// action type 1
{key: 'PLUS'}

// action type 2
{key: 'MINUS'}

  • action type은 dispatch의 파라미터로 담겨 전송된다.
const dispatch = useDispatch();
//.. 중략

dispatch({type: 'PLUS'}) // PLUS action을 dispatch 했다.

InitialState

  • 각각의 Reducer에서의 초기상태값 묶음 또는 초기값이다.
  • reducer의 파라미터에서 default 값으로 넣어주도록 하자.

Action creator

  • 뜻 그대로 action type을 만들어주는 함수입니다.
  • 왜 굳이 함수를 사용해서 action type을 만드는 이유는, 만약 {type : ‘PLUS’} 라는 액션을 10개의 컴포넌트에서 dispatch 한다고 해볼게요. 그렇다면 10개의 컴포넌트에서 {type : ‘PLUS’} 라는 코드를 매번 하드 코딩해야 하는 불편함이 있고 또한 오타를 비롯한 예상치 못한 에러가 있을 수 있어요. 그래서 보통 {type : ‘PLUS’} 을 생성하는 함수를 통해 action type을 생성합니다.
  • 코드로 확인하기
  • // action creator export const plus = () => { return {type : 'PLUS'} } // action creator를 이용해서 dispatch 하기 dispatch(plus())

Reducer

  • dispatch는 reducer에게 action을 전달해준다. reducer는 action을 보고 그 행동을 수행하여 새로운 state를 반환하는 역할을 한다. 마치 식당에서 주문서(action)를 받아 요리를 하여, 요리(state)를 내어주는 요리사와 비슷하다고 생각하면 된다.
  • reducer은 조건문을 가진 함수 = function 이다. 또한 파라미터에서는 store의 state값과 disaptch가 전달해준 action을 받을 수 있다.
  • 코드로 확인하기
  • // 초기값 const initialState = 0; // 보통 switch문을 사용하여 reducer을 작성하곤 한다. const reducer = (state = initialState, action) => { switch(action.type){ case PLUS: return {...} case MINUS: return {...} default: return state } }

useDispatch

  • react에서 redux를 사용하기 위해서는 react-redux라는 라이브러리를 같이 사용해야 한다. react-redux의 제공하는 리덕스 훅이다. function component 에서 리덕스를 쓰는 경우에는 useDispatch를 통해 간단하게 dispatch 할 수 있다.

<aside> 💡 redux는 react에서만 쓸 수 있는 기술이 아닙니다. 바닐라 JS, Vue 등 다른 환경에서도 사용 할 수 있는데, react-redux는 redux와 react를 이어주는 역할을 합니다.

</aside>

useSelect

  • Store에 있는 상태 = 값 들을 꺼내올 때 사용합니다.
  • const state = useSelector(state => state); console.log(state) // 무엇이 보이는지 콘솔에 찍어보세요!

코드로 보는 리덕스의 흐름


  1. 컴포넌트에서 dispatch를 실행
    1. 개발자(나)는 업데이트를 원하는 Store state가 있었을 때 action을 dispatch 한다.
    • 코드로 확인하기
    • // src/pages/Component.js import { useDispatch } from 'react-redux'; const Component = () => { const dispatch = useDispatch(); // 버튼을 누르면, PLUS 이라는 action type을 담아 dispatch 한다. const onClickHandler = () => { dispatch({type: 'PLUS'}); } return <button onClick={onClickHandler}>더하기 버튼</button> } export default Component;
  2. dispatch는 reducer에게 action을 전달
    1. dispatch를 통해 전달받은 action을 확인해보자.
    • 코드로 확인하기
    • // src/modules/calculate.js const initialState = 0; const reducer = (state = initialState, action) => { console.log(action) // {type: 'PLUS'}가 보인다. dispatch가 전달해준 것이다. switch(action.type){ case PLUS: return state + 1; case MINUS: return state - 1; default: return state } }
  3. reducer는 전달받은 action이 무엇인지 확인하고, 새로운 상태값을 반환
    1. action.type이 PLUS 인 것을 찾아 reducer는 기존 state값에 +1을 한 1 을 반환한다.
  4. store의 state값이 새로운 값으로 변경됨
    1. 반환된 1 이 store의 state 값으로 적용된다.
  5. 컴포넌트에서는 새로운 값을 useSelect을 통해 수신하고, 화면에 렌더링
    1. 이제 화면에서 새롭게 업데이트 된 store의 state 값을 가져와보자.
    • 코드로 확인하기
    • import { useDispatch, useSelector } from 'react-redux'; const Component = () => { const dispatch = useDispatch(); // redux에서 값을 가져올때는 useSelector를 사용한다. const number = useSelector(state => state.calculate); // 버튼을 누르면, PLUS 이라는 action type을 담아 dispatch 한다. const onClickHandler = () => { dispatch({type: 'PLUS'}); } return ( <> <div>{number}</div> {/* 가져온 값을 렌더링 해보자. */} <button onClick={onClickHandler}>더하기 버튼</button> </> ) } export default Component;

그래서, 뭐부터 해야 되나요?


modules 파일 만들기

  1. src 폴더에 “modules” 이라는 폴더를 만들어주세요. 폴더의 이름은 중요하지 않지만 보통은 modules 또는 “redux” 로 이름을 지어서 사용합니다. (폴더 이름은 개발자 (나) 마음입니다 = 마음대로 하세요.)

설정하기

  1. 강의를 보고 설정을 해주세요. 설정은 처음에 한번 만 하면 됩니다. 그리고 설정을 하면서 작성하는 코드들이 이해가 되지 않아도 괜찮습니다. 왜냐하면, 이건 단지 설정 이기때문에 아직은 여러분들에게 중요한 코드들도 아니고, 이해를 할 필요도 없습니다. 이해 하려고 노력하지 마세요.

[중요 ‼️ ] ducks 패턴 파일 만들기

리덕스의 구성요소 action type, action creator, initialState, reducer를 작성하는게 리덕스 로직을 구현한다라고 해도 과언이 아닙니다. 우리가 redux에서 중점적으로 공부해야 할 것은 위 구성요소를 견고하고 정확하게 작성하는 방법 입니다.

  1. 계산기 기능에 대한 모듈 파일을 만들어볼까요?
    • 구성요소를 작성해보세요.
    • // src/modules/calculate.js // action type // 액션 타입을 생성하세요. // action creator // 액션 타입 생성 함수를 작성하세요. // initialState // 이 모듈의 초기값을 설정해주세요. // reducer // 리듀서를 만들어주세요. // 그리고 이 파일에서 export 하는 것은 reducer여야 합니다. export default reducer;

컴포넌트에서 dispatch, useSelector 하기

  1. dispatch, useSelect 로직을 작성해볼까요?
    • 코드로 확인하기
    • // src/pages/CalculateHome.js const CalculateHome = () => { return <div></div> } export default CalculateHome;

TIP


  1. 모듈 파일을 만드는 연습을 많이하세요. 비어있는 파일에서 아무 자료도 참고하지 않고 action type, action creator, reducer를 작성할 수 있을 때까지 연습하세요. 외우는 것도 방법입니다.
  2. 리덕스의 구성요소가 어떤 데이터 타입인지 반드시 기억하세요.
    1. action type은 type을 가진 객체다.
    2. reducer는 새로운 상태값을 반환하는 함수다.
    3. action creator는 action type을 반환하는 함수다.
  3. 설정 코드를 이해하려고 하지 마세요.
  4. 리덕스의 흐름을 그림으로 직접 그려보세요.

왜 미들웨어를 써야 하나요?


dispatch 하는 과정 안에서 개발자가 추가 동작을 하고 싶기 때문입니다. 만약 유저가 버튼을 눌렀을 때 3초 후에 +1이 되는 기능을 만드는 개발자라고 가정해볼게요. 아마 아래의 과정이 필요할 거에요.

1. button 클릭한다. = dispatch(plus())
2. 3초를 기다린다.
3. +1를 더한다.

하지만 미들웨어를 쓰지 않은 리덕스에서는 3초를 기다린다 라는 동작을 할 수 없어요. dispatch를 하는 즉시 reducer에 action type을 건네주기 때문이죠. 이렇게 무언가 리덕스의 흐름에서 개발자가 추가로 어떤 동작을 하고자 할 때 미들웨어를 사용합니다. 그리고 보통 추가동작 이라고 한다면, ‘서버와의 통신’ 이라는 동작일 확률이 가장 높습니다.

Redux-thunk


리덕스의 미들웨어에는 여러가지 있는데, 그 중 이번 프로젝트에서 사용할 것은 Redux-thunk 입니다. 이것을 사용하면 무엇이 가능해지냐면 dispatch()에 인자에 action type 객체가 아닌 함수를 넣을 수 있게 됩니다.

<aside> ‼️ 기본 리덕스에서 dispatch()는 인자에는 반드시 action type 객체가 들어가야만 합니다.

</aside>

하지만, redux-thunk를 사용하는 순간부터는 함수 가 들어갈 수 있습니다. 우리는 그 함수를 thunk 함수라고 부릅니다. 그리고 우리 개발자들은 ‘추가동작'을 이 thunk 함수 안에다가 구현하면 됩니다. 모든 추가 동작이 끝나면 원래 하고자 했던 dispatch를 다시 해서 reducer를 작동시킵니다.

Redux-thunk를 사용했을 때 흐름을 볼까요?

  1. dispatch(Thunk function)
  2. thunk function 실행되고, 개발자가 작성한 추가동작들이 실행
  3. dispatch(action type)
  4. Reducer가 action type을 전달받아 새로운 상태값을 반환합니다.

Thunk Function


thunk 함수는 이렇게 생겼습니다. 함수를 반환하는 함수 입니다. 이러한 함수를 고차함수라고 부릅니다. 다만 지금 당장은 이 고차함수의 원리보다도 thunk 함수를 생성하고 사용하는 방법에 집중해봅시다.

const thunkFunction = (args) => (dispatch, getState) => {
	// 추가동작 구현

  // 하고자 했던 action type dispatch
  dispatch(plus())
};

이렇게, redux-thunk 를 사용하여 thunk 함수를 생성, 추가 동작을 할 수 있습니다. 우리는 보통 서버와의 통신을 이 thunk 함수 안에서 하게 될 것입니다.

728x90

'Web > React' 카테고리의 다른 글

React Redux  (0) 2022.05.27
명령형 vs 선언형 프로그래밍  (0) 2022.05.27
React - Redux Toolkit  (0) 2022.05.26
React - Redux  (0) 2022.05.26
React - Github IO  (0) 2022.05.22