Redux 및 미들웨어 Redux-saga 기본 정리 및 적용

SeoYng·2020년 11월 13일
3
post-thumbnail

react redux와 Redux-saga에 대해 알아보고 간단히 사용해보자

🔎 Redux

Redux란 ?
가장 많이 쓰이는 상태관리 라이브러리.
컴포넌트 끼리 상태(데이터, 로직)를 공유하게 될 때 여러 컴포넌트를 거치지 않고 바로 상태 값을 전달하거나 받아볼 수 있게 해준다. 우체국 같은 느낌?

🤔 필요성

글로벌 상태 관리를 하게 될 때 굉장히 효과적 !

props 가 필요한 곳으로 전달되게 하기 위해 해당 props 를 사용하지 않는 컴포넌트를 거쳐가야 해서 불필요한 리렌더링이 발생하고, 이를 전달하는 것은 굉장히 귀찮은 작업이 된다.

🤔 개념

액션 (Action)

객체의 형태로 표현되며 상태변화/조회 등이 필요할 때 발생시킨다.
액션을 설명하는 type 필드를 필수적으로 가지고 있어야하고 그 외의 값들은 마음대로 넣을 수 있다.

{
  type: "ADD_COUNT",
}
{
  type: "TOGGLE_TODO",
  id: 0
}
{
  type: "ADD_TODO",
  data:{
    id: 0,
    content: "",
    done: false
  }
}
// 액션 타입 정의
const ADD_TODO = 'ADD_TODO';
const TOGGLE_TODO = 'TOGGLE_TODO';
const ADD_COUNT = 'ADD_COUNT';

액션 생성함수 (Action Creator)

액션을 만드는 함수로 파라미터를 받아와서 액션 객체 형태로 만들어주는 역할을 한다.

function toggleTodo = id => ({
  return {
    type: "TOGGLE_TODO",
    id
});

리듀서 (Reducer)

state와 action을 파라미터로 받아와서 변화를 일으키는 함수

// 초깃값 설정
const initialState = [],

// reducer 함수 정의
function reducer(state = initialState, action) {
  switch (action.type) {
    case ADD_TODO:
      return state.concat(action.data);
    case TOGGLE_TODO:
      return state.map(data => data.id === action.id ? {
      	...todo, done:todo.done!
      });
    ...
    default:
      // 지원하지 않는 액션은 상태 유지
      return state;
  }
}

스토어 (Store)

상태와 리듀서, 내장함수들이 저장되어 있는 곳.
한 애플리케이션 당 하나의 스토어 사용

import { createStore } from 'redux';

const store = createStore(reducer);

디스패치 (dispatch)

스토어의 내장함수 중 하나로 액션을 발생 시키는 것을 말한다.

dispatch(toggleSwitch())

구독 (subscribe)

스토어의 내장함수 중 하나로 함수 형태의 값을 파라미터로 받아 액션이 디스패치 되었을 때 전달해준 함수가 호출된다.
react와 함께쓰면 이미 기능이 내장되어 있어 사용할 일은 없을 가능성이 많다.

const listener = () => console.log('업데이트 됐어요!')
const unsubscribe = store.subscribe(listener);
// subscribe 함수는 구독 기능을 끄는 unsubscribe 반환

🧚 리덕스 적용해보기

👀 깃헙 링크

패키지 설치

$ yarn add redux
$ yarn add react-redux

member 모듈 생성

📃 src/modules/member.js

// 액션 타입 설정
const SET_MEMBERS = 'member/SET_MEMBERS';

// 액션 생성 함수 - export
export const setMembersToStore = members => ({
  type: SET_MEMBERS,
  members,
});

// 초깃값 설정
const initialState = {
  members: [],
};

// reducer 함수 정의 - export default
export default function reducer(state = initialState, action) {
  switch (action.type) {
    case SET_MEMBERS:
      console.log('a :', action);
      return {
        ...state,
        members: action.members,
      };
    default:
      // 지원하지 않는 액션은 상태 유지
      return state;
  }
}

dispatch 정의 및 호출

📃 MemberList.js

...
// redux 사용
import { setMembersToStore } from '../../modules/member';
import { useDispatch } from 'react-redux';

// action dispatch 정의
  const dispatch = useDispatch();
  const saveMembersToStore = data => dispatch(setMembersToStore(data));

// dispatch 호출
  useEffect(() => {
    (async () => {
      const { data } = await getMembers();
      ...
      // store에 저장
      saveMembersToStore(data);
    })();
  }, []);

reducer combine해서 내보내기

📃 modules/index.js

import { combineReducers } from 'redux';
import member from './member';

const rootReducer = combineReducers({
  member,
});

export default rootReducer;

react에 store 적용

📃 index.js

...
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './modules';
// store 생성
const store = createStore(rootReducer);
console.log(store.getState());
//{member: { members: [] }

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
  document.getElementById('root'),
);

Main 페이지에서 잘 저장되어있는지 보기

📃 Main.js

// 스토에어서 불러오기
import { useSelector } from 'react-redux';

function Main() {
  // 스토어
  const { members } = useSelector(state => state.member);
  console.log('saved members : ', members);
  ...
}
// [] -> [{}, {} ...]

🧚 결과

Object
member:
members: Array(0)

[SUCCESS] GET MEMBERS ---->

Object
data: (13) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…

🔎 Redux-saga

Redux-saga ?
리덕스의 미들웨어로 비동기 작업, 로깅 등의 확장적인 작업들을 할 수 있게 해준다.
액션을 모니터링하고 있다가, 특정 액션이 발생하면 이에 따라 특정 작업을 하는 방식으로 사용한다.

🤔 필요성

특정 액션이 발생했을 때 상태 값이나 응답 상태 등에 따라 다른 액션을 디스패치 하거나 추가적인 로직을 적용 해야될 때 사용할 수 있다.

🤔 장점 및 기능

  • 비동기 작업을 할 때 기존 요청을 취소 처리
  • 웹소켓을 사용시 Channel 이라는 기능을 사용하여 효율적으로 코드를 관리
  • API 요청이 실패했을 때 재요청하는 작업 가능

🤔 effects 패키지의 함수들

delay

특정시간 후 함수를 실행할 수 있게 해준다.

import { delay } from 'redux-saga/effects';
function* toggleTodoSaga() { // 제너레이터 함수 형태
  yield delay(1000);
}

put

특정 액션을 디스패치 해준다.

import { put } from 'redux-saga/effects';
function* toggleTodoSaga() {
  ...
  yield put(toggleTodo()); // put은 특정 액션을 디스패치 해줍니다.
}

call

다특정 함수를 호출하고, 결과물이 반환 될 때까지 기다릴 수 있어 동기적 실행이 가능하다.

import { call } from 'redux-saga/effects';
import * as todosAPI from '../api/todos'
function* toggleTodoSaga() {
  const todo = yield call(postsAPI.getTodoById, param);
  ...
}

등등


👀 Redux 참고 블로그

👀 Redux-saga 참고 블로그

profile
Junior Web FE Developer

0개의 댓글