๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

react/redux

[React] redux-saga ์‹œ์ž‘ํ•˜๊ธฐ! ๊ธฐ๋ณธ์ ์ธ effects ํ™œ์šฉ

๐Ÿ’ฅ redux-saga

  • ๋น„๋™๊ธฐ ์ž‘์—…์„ ํ•˜๋Š” ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • ํŠน์ • ์•ก์…˜์ด ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ƒํƒœ ๊ฐ’์ด๋‚˜ ์‘๋‹ต ์ƒํƒœ ๋“ฑ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์•ก์…˜์„ ๋””์ŠคํŒจ์น˜ ํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€์ ์ธ ๋กœ์ง์„ ์ ์šฉ ํ•ด์•ผ๋  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • api์š”์ฒญ, ์š”์ฒญ ์‹คํŒจ ์‹œ ์žฌ์š”์ฒญ ๋“ฑ์˜ ๋ฆฌ๋•์Šค์™€ ๊ด€๊ณ„์—†๋Š” ์ฝ”๋“œ๋ฅผ ๋ฏธ๋“ค์›จ์–ด๋กœ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
    yarn add redux-saga ๋˜๋Š” npm install redux-saga

 

โ— generator ํ•จ์ˆ˜

  • generator ํ•จ์ˆ˜๋Š” ์ผ๋ฐ˜ ํ•จ์ˆ˜์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ํ•จ์ˆ˜ ์ฝ”๋“œ ์‹คํ–‰์„ ์ผ์‹œ ์ค‘์ง€ํ–ˆ๋‹ค๊ฐ€ ํ•„์š”ํ•œ ์‹œ์ ์— ์žฌ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜์ด๋‹ค.
  • yield๋Š” ์ค‘๋‹จ์ ์„ ๋งŒ๋“ ๋‹ค.
  • yield ๋’ค์— ๊ฐ’์ด ์žˆ์œผ๋ฉด ๊ทธ๊ฑธ ๊ฐ์ฒด์˜ value์— ๋‹ด์•„ returnํ•˜๊ณ  ๋ฉˆ์ถ˜๋‹ค.
  • ์•„๋ž˜์™€ ๊ฐ™์ด function*๋กœ ์„ ์–ธํ•œ๋‹ค.
  • next()๋ฅผ ํ†ตํ•ด์„œ ๋‹ค์Œ ์ค‘๋‹จ์ ๊นŒ์ง€ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

 

โ— ์ž์ฃผ ์“ฐ์ด๋Š” effects

import {all, fork, take, call, put} from 'redux-saga/effects';

import {all, fork, take, call, put} from 'redux-saga/effects';
  • effect๋Š” yield๋’ค์— ์˜ค๋Š” ํ•จ์ˆ˜๋กœ, ๊ฐ์ž์˜ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • take
    ํ•ด๋‹น ์•ก์…˜์ด dispatch๋˜๋ฉด ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ nextํ•œ๋‹ค.
  function* watchLogIn() {
 	 yield take('LOG_IN', logIn); // 'LOG_IN'์ด ๋“ค์–ด์˜ค๋ฉด logIn ํ•จ์ˆ˜ ์‹คํ–‰
  }
  • put
    ํŠน์ • action์„ dispatch ์‹œ์ผœ์ค€๋‹ค.
    ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ๋Š” ์•ก์…˜ ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค.
    yield put({
        type: 'LOG_IN_SUCCESS',
        data: result.data
    });
  • takeEvery
    ๋ชจ๋“  ํ•ด๋‹น ์•ก์…˜์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • takeLatest
    ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์œผ๋กœ dispatch๋œ ์•ก์…˜์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • all
    ์—ฌ๋Ÿฌ ์‚ฌ๊ฐ€๋ฅผ ํ•ฉ์ณ์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. all์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐฐ์—ด์„ ๋ฐ›๋Š”๋ฐ, ๋ฐฐ์—ด ๋‚ด์— ์žˆ๋Š” ๊ฒƒ์„ ๋ชจ๋‘ ์‹คํ–‰์‹œํ‚จ๋‹ค.
  • call
    ํ•จ์ˆ˜๋ฅผ ๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰์‹œ์ผœ์ค€๋‹ค. ์ฒซ๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ํ•จ์ˆ˜, ๋‘๋ฒˆ์งธ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ํ•ด๋‹น ํ•จ์ˆ˜์— ๋„ฃ์„ ์ธ์ˆ˜์ด๋‹ค.
   yield call(request, action.payload)
  • fork
    call๊ณผ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๊ฐ™๊ณ  ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” ์—ญํ• ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋น„๋™๊ธฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ณผ๊ฐ’์„ ๊ธฐ๋‹ค๋ ค ์ฃผ์ง€ ์•Š๋Š”๋‹ค.
    export default function* rootSaga() {
    	yield all([
    		fork(ํ•จ์ˆ˜),
    		fork(ํ•จ์ˆ˜)
    	])
    }

 

๐Ÿ’ฅ ๊ธฐ์ดˆ ๊ตฌํ˜„ ์ฝ”๋“œ

import {all, fork, take, call, put} from 'redux-saga/effects';
import axios from 'axios';

function logInAPI(data) {
    return axios.post('url/api/login', data);
}

function* logIn(action) {
    try {
        const result = yield call(logInAPI, action.data);
				// logInAPI์— ์ „๋‹ฌํ•  ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ call์˜ ๋‘๋ฒˆ์งธ ํŒŒ๋ฆฌ๋ฏธํ„ฐ๋กœ ์ง€์ •ํ•ด์ค€๋‹ค. 
				// action์ด login์— ๋Œ€ํ•œ ์•ก์…˜์ด๋‹ˆ๊นŒ action.data์— ๋‚ด๊ฐ€ ๋„ฃ์–ด๋‘” ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด์žˆ๋‹ค.
        yield put({
            type: 'LOG_IN_SUCCESS',
            data: result.data
        });
    } catch (err) {
        yield put({
            type: 'LOG_IN_FAILURE',
            data: err.response.data
        });
    }
}

function* watchLogIn() {
    yield take('LOG_IN', logIn); // login์— ๋Œ€ํ•œ ์•ก์…˜ ์ž์ฒด๊ฐ€ logIn์— ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋œ๋‹ค.
}


// (a) ์•ก์…˜์„ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์‹ถ์€ ์‹œ์ ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด dispatch! 
dispatch(login({data: user}));
  • ์˜ˆ๋ฅผ ๋“ค์–ด ๋‚ด๊ฐ€ LOG_IN ์•ก์…˜์— ๋Œ€ํ•œ ์•ก์…˜ ์ƒ์„ฑํ•จ์ˆ˜๋ฅผ login์œผ๋กœ ๋งŒ๋“ค์—ˆ์„ ๋•Œ
  • ํ•ด๋‹น ์•ก์…˜์„ ๋ฐœ์ƒ์‹œํ‚ค๊ณ  ์‹ถ์€ ์‹œ์ ์—์„œ (a) ๊ฐ™์ด dispatchํ•˜๋ฉด
  • watchLogInํ•จ์ˆ˜ ๋‚ด์˜ take์—์„œ ๋ฐ›์•„์„œ logIn generatorํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚จ๋‹ค.
  • ์ด๋•Œ, logIn์˜ ํŒŒ๋ผ๋ฏธํ„ฐ action์œผ๋กœ๋Š” ๋‚ด๊ฐ€ dispatchํ•œ ์•ก์…˜ ์ž์ฒด๊ฐ€ ๋“ค์–ด์˜จ๋‹ค. (์ฆ‰ action.data๋Š” ๋‚ด๊ฐ€ ๋„ฃ์€ user)
  • ๊ทธ ๊ฐ’์œผ๋กœ axios์š”์ฒญ์„ ํ•˜๊ณ  ์„ฑ๊ณตํ•˜๋ฉด LOG_IN_SUCCESS put
  • ์‹คํŒจํ•˜๋ฉด LOG_IN_FAILURE์„ putํ•œ๋‹ค.
  • ๊ฐ๊ฐ LOG_IN_SUCCESS์™€ LOG_IN_FAILURE์— ๋Œ€ํ•ด์„œ ์„ฑ๊ณต ์‹œ state๋ฅผ ๋ฐ”๊พธ๋Š” ๋“ฑ์˜ ์ฝ”๋“œ๋ฅผ ๋ฆฌ๋“€์„œ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

 

๋ฐ˜์‘ํ˜•