์นดํ…Œ๊ณ ๋ฆฌ ๋ณด๊ด€๋ฌผ: Javascript

Javascript

ES6 ์ƒ์„ฑ๊ธฐ์™€ ํ•จ๊ป˜ redux-saga ์‚ฌ์šฉ vs ES2017๊ณผ ํ•จ๊ป˜ redux-thunk ์‚ฌ์šฉ์˜ ์žฅ๋‹จ์  async / await <input type=โ€passwordโ€ ref=โ€passโ€

redux-saga / redux-saga์˜ redux ํƒ€์šด์—์„œ ์ตœ์‹  ์•„์ด์— ๋Œ€ํ•ด ๋งŽ์€ ์ด์•ผ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž‘์—… ๋“ฃ๊ธฐ / ๋ฐฐํฌ๋ฅผ ์œ„ํ•ด ์ƒ์„ฑ๊ธฐ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋จธ๋ฆฌ๋ฅผ ๊ฐ์‹ธ๊ธฐ ์ „์— async / await๊ณผ ํ•จ๊ป˜ redux-saga์‚ฌ์šฉ redux-thunkํ•˜๋Š” ์•„๋ž˜์˜ ์ ‘๊ทผ ๋ฐฉ์‹ ๋Œ€์‹  ์‚ฌ์šฉ์˜ ์žฅ๋‹จ์ ์„ ์•Œ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค .

๊ตฌ์„ฑ ์š”์†Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ‰์†Œ์™€ ๊ฐ™์ด ์ž‘์—…์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

import { login } from 'redux/auth';

class LoginForm extends Component {

  onClick(e) {
    e.preventDefault();
    const { user, pass } = this.refs;
    this.props.dispatch(login(user.value, pass.value));
  }

  render() {
    return (<div>
        <input type="text" ref="user" />
        <input type="password" ref="pass" />
        <button onClick={::this.onClick}>Sign In</button>
    </div>);
  }
}

export default connect((state) => ({}))(LoginForm);

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‚ด ํ–‰๋™์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// auth.js

import request from 'axios';
import { loadUserData } from './user';

// define constants
// define initial state
// export default reducer

export const login = (user, pass) => async (dispatch) => {
    try {
        dispatch({ type: LOGIN_REQUEST });
        let { data } = await request.post('/login', { user, pass });
        await dispatch(loadUserData(data.uid));
        dispatch({ type: LOGIN_SUCCESS, data });
    } catch(error) {
        dispatch({ type: LOGIN_ERROR, error });
    }
}

// more actions...

// user.js

import request from 'axios';

// define constants
// define initial state
// export default reducer

export const loadUserData = (uid) => async (dispatch) => {
    try {
        dispatch({ type: USERDATA_REQUEST });
        let { data } = await request.get(`/users/${uid}`);
        dispatch({ type: USERDATA_SUCCESS, data });
    } catch(error) {
        dispatch({ type: USERDATA_ERROR, error });
    }
}

// more actions...


๋‹ต๋ณ€

redux-saga์—์„œ ์œ„์˜ ์˜ˆ์™€ ๋™๋“ฑํ•œ ๊ฒƒ์€

export function* loginSaga() {
  while(true) {
    const { user, pass } = yield take(LOGIN_REQUEST)
    try {
      let { data } = yield call(request.post, '/login', { user, pass });
      yield fork(loadUserData, data.uid);
      yield put({ type: LOGIN_SUCCESS, data });
    } catch(error) {
      yield put({ type: LOGIN_ERROR, error });
    }
  }
}

export function* loadUserData(uid) {
  try {
    yield put({ type: USERDATA_REQUEST });
    let { data } = yield call(request.get, `/users/${uid}`);
    yield put({ type: USERDATA_SUCCESS, data });
  } catch(error) {
    yield put({ type: USERDATA_ERROR, error });
  }
}

๊ฐ€์žฅ ๋จผ์ € ์•Œ์•„์•ผ ํ•  ๊ฒƒ์€ form์„ ์‚ฌ์šฉํ•˜์—ฌ api ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๋Š” ๊ฒƒ yield call(func, ...args)์ž…๋‹ˆ๋‹ค. callํšจ๊ณผ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ ์™€ ๊ฐ™์€ ์ผ๋ฐ˜ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค {type: 'CALL', func, args}. ์‹คํ–‰์€ ๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋กœ ์ƒ์„ฑ๊ธฐ๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋Š” redux-saga ๋ฏธ๋“ค์›จ์–ด์— ์œ„์ž„๋ฉ๋‹ˆ๋‹ค.

์ฃผ์š” ์ด์ ์€ ๊ฐ„๋‹จํ•œ ๋“ฑ์‹ ๊ฒ€์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Redux ์™ธ๋ถ€์—์„œ ๋ฐœ์ „๊ธฐ๋ฅผ ํ…Œ์ŠคํŠธ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค

const iterator = loginSaga()

assert.deepEqual(iterator.next().value, take(LOGIN_REQUEST))

// resume the generator with some dummy action
const mockAction = {user: '...', pass: '...'}
assert.deepEqual(
  iterator.next(mockAction).value,
  call(request.post, '/login', mockAction)
)

// simulate an error result
const mockError = 'invalid user/password'
assert.deepEqual(
  iterator.throw(mockError).value,
  put({ type: LOGIN_ERROR, error: mockError })
)

์šฐ๋ฆฌ๋Š” ๋‹จ์ˆœํžˆ ๋ชจ์˜ ๋ฐ์ดํ„ฐ๋ฅผ next๋ฐ˜๋ณต์ž ์˜ ๋ฉ”์†Œ๋“œ์— ์ฃผ์ž…ํ•˜์—ฌ API ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ์˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค . ๋ฐ์ดํ„ฐ ๋ชจ์˜๋Š” ๋ชจ์˜ ํ•จ์ˆ˜๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ๋กœ ์•Œ์•„์•ผ ํ•  ๊ฒƒ์€์— ๋Œ€ํ•œ ํ˜ธ์ถœ yield take(ACTION)์ž…๋‹ˆ๋‹ค. ์ฝ ํฌ๋Š” ๊ฐ๊ฐ์˜ ์ƒˆ๋กœ์šด ์•ก์…˜ (์˜ˆ :)์—์„œ ์•ก์…˜ ์ œ์ž‘์ž๊ฐ€ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค LOGIN_REQUEST. ์ฆ‰, ์•ก์…˜์€ ์ง€์†์  ์œผ๋กœ ์ฝํฌ์— ํ‘ธ์‹œ ๋˜๋ฉฐ ์ฝ ํฌ๋Š” ์ด๋Ÿฌํ•œ ์•ก์…˜์˜ ์ฒ˜๋ฆฌ๋ฅผ ์ค‘์ง€ ํ• ์‹œ๊ธฐ๋ฅผ ์ œ์–ด ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

REDUX โ€“ ์‚ฌ๊ฐ€์—์„œ, ๋ฐœ์ „๊ธฐ๋Š” ํ’€ ๋‹ค์Œ ์กฐ์น˜๋ฅผ. ์ฆ‰, ์–ด๋–ค ํ–‰๋™์„๋“ค์„ ๋•Œ์™€ํ•˜์ง€ ๋ง์•„์•ผ ํ• ์‹œ๊ธฐ๋ฅผ ํ†ต์ œ ํ•  ์ˆ˜์žˆ๋‹ค. ์œ„์˜ ์˜ˆ์ œ์—์„œ ํ๋ฆ„ ๋ช…๋ น์€ while(true)๋ฃจํ”„ ๋‚ด๋ถ€์— ๋ฐฐ์น˜ ๋˜๋ฏ€๋กœ ๊ฐ ๋“ค์–ด์˜ค๋Š” ๋™์ž‘์„ ์ˆ˜์‹ ํ•˜์—ฌ ์ฝํฌ ํ‘ธ์‹œ ๋™์ž‘์„ ๋ชจ๋ฐฉํ•ฉ๋‹ˆ๋‹ค.

ํ’€ ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ๋ณต์žกํ•œ ์ œ์–ด ํ๋ฆ„์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถ”๊ฐ€ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

  • LOGOUT ์‚ฌ์šฉ์ž ์กฐ์น˜ ์ฒ˜๋ฆฌ

  • ์ฒซ ๋ฒˆ์งธ ๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•˜๋ฉด ์„œ๋ฒ„๋Š” expires_inํ•„๋“œ์— ์ €์žฅ๋œ ์ง€์—ฐ ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ† ํฐ์„ ๋ฐ˜ํ™˜ ํ•ฉ๋‹ˆ๋‹ค. expires_in๋ฐ€๋ฆฌ ์ดˆ ๋งˆ๋‹ค ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์ธ์ฆ์„ ์ƒˆ๋กœ ๊ณ ์นจํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

  • API ํ˜ธ์ถœ์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆด ๋•Œ (์ดˆ๊ธฐ ๋กœ๊ทธ์ธ ๋˜๋Š” ์ƒˆ๋กœ ๊ณ ์นจ) ์‚ฌ์šฉ์ž๊ฐ€ ์ค‘๊ฐ„์— ๋กœ๊ทธ ์•„์›ƒ ํ•  ์ˆ˜ ์žˆ์Œ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค.

์ฝ ํฌ๋กœ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜๊ฒ ์Šต๋‹ˆ๊นŒ? ๋˜ํ•œ ์ „์ฒด ํ๋ฆ„์— ๋Œ€ํ•œ ์ „์ฒด ํ…Œ์ŠคํŠธ ๋ฒ”์œ„๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๊นŒ? Sagas์—์„œ ์–ด๋–ป๊ฒŒ ๋ณด์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

function* authorize(credentials) {
  const token = yield call(api.authorize, credentials)
  yield put( login.success(token) )
  return token
}

function* authAndRefreshTokenOnExpiry(name, password) {
  let token = yield call(authorize, {name, password})
  while(true) {
    yield call(delay, token.expires_in)
    token = yield call(authorize, {token})
  }
}

function* watchAuth() {
  while(true) {
    try {
      const {name, password} = yield take(LOGIN_REQUEST)

      yield race([
        take(LOGOUT),
        call(authAndRefreshTokenOnExpiry, name, password)
      ])

      // user logged out, next while iteration will wait for the
      // next LOGIN_REQUEST action

    } catch(error) {
      yield put( login.error(error) )
    }
  }
}

์œ„์˜ ์˜ˆ์—์„œ๋Š”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์‹œ์„ฑ ์š”๊ตฌ ์‚ฌํ•ญ์„ ํ‘œํ˜„ํ•˜๊ณ  race์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒฝ์šฐ take(LOGOUT)์Šน๋ฆฌ ๊ฒฝ์ฃผ (์ฆ‰, ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ ์•„์›ƒ ๋ฒ„ํŠผ ํด๋ฆญ). ๋ ˆ์ด์Šค๋Š” authAndRefreshTokenOnExpiry๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์„ ์ž๋™์œผ๋กœ ์ทจ์†Œํ•ฉ๋‹ˆ๋‹ค . ๊ทธ๋ฆฌ๊ณ  ํ†ตํ™” authAndRefreshTokenOnExpiry๋„์ค‘์—์ด ์ฐจ๋‹จ ๋œ ๊ฒฝ์šฐ call(authorize, {token})์—๋„ ์ทจ์†Œ๋ฉ๋‹ˆ๋‹ค. ์ทจ์†Œ๋Š” ์ž๋™์œผ๋กœ ์•„๋ž˜์ชฝ์œผ๋กœ ์ „ํŒŒ๋ฉ๋‹ˆ๋‹ค.

์œ„์˜ ํ๋ฆ„์— ๋Œ€ํ•œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ๋ฐ๋ชจ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค


๋‹ต๋ณ€

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž‘์„ฑ์ž์˜ ์ฒ ์ €ํ•œ ๋‹ต๋ณ€ ์™ธ์—๋„ ํ”„๋กœ๋•์…˜ ์‹œ์Šคํ…œ์—์„œ saga๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝํ—˜์„ ์ถ”๊ฐ€ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ”„๋กœ (์‚ฌ๊ฐ€ ์‚ฌ์šฉ) :

  • ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ์„ฑ. call ()์ด ์ˆœ์ˆ˜ํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— sagas๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ฝํฌ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ ค๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ํ…Œ์ŠคํŠธ ๋‚ด์— mockStore๋ฅผ ํฌํ•จํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

  • redux-saga์—๋Š” ์ž‘์—…์— ๋Œ€ํ•œ ์œ ์šฉํ•œ ๋„์šฐ๋ฏธ ๊ธฐ๋Šฅ์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. saga์˜ ๊ฐœ๋…์€ ์•ฑ์— ๋Œ€ํ•œ ์ผ์ข…์˜ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์›Œ์ปค / ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

  • Sagas๋Š” ๋ชจ๋“  ๋ถ€์ž‘์šฉ์„ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜์žˆ๋Š” ๋…๋ฆฝ์  ์ธ ์žฅ์†Œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋‚ด ๊ฒฝํ—˜์—์„œ ์ฝํฌ ์ž‘์—…๋ณด๋‹ค ์ˆ˜์ •ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค.

๋ฒ”์ฃ„์ž:

  • ์ƒ์„ฑ๊ธฐ ๊ตฌ๋ฌธ.

  • ๋ฐฐ์šธ ๊ฐœ๋…์ด ๋งŽ์Šต๋‹ˆ๋‹ค.

  • API ์•ˆ์ •์„ฑ. redux-saga๋Š” ์—ฌ์ „ํžˆ ๊ธฐ๋Šฅ (์˜ˆ : ์ฑ„๋„?)์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์ปค๋ฎค๋‹ˆํ‹ฐ๋Š” ๊ทธ๋ฆฌ ํฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์–ธ์  ๊ฐ€ ์ด์ „ ๋ฒ„์ „๊ณผ ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ์—…๋ฐ์ดํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.


๋‹ต๋ณ€

๋‚ด ๊ฐœ์ธ์ ์ธ ๊ฒฝํ—˜ (sagas์™€ thunk๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜์—ฌ)์— ๋Œ€ํ•œ ์˜๊ฒฌ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

Sagas๋Š” ํ…Œ์ŠคํŠธํ•˜๊ธฐ์— ์ข‹์Šต๋‹ˆ๋‹ค.

  • ํšจ๊ณผ๋กœ ๊ฐ์‹ธ ์ง„ ํ•จ์ˆ˜๋ฅผ ์กฐ๋กฑ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
  • ๋”ฐ๋ผ์„œ ํ…Œ์ŠคํŠธ๋Š” ๊นจ๋—ํ•˜๊ณ  ์ฝ๊ธฐ ์‰ฝ๊ณ  ์ž‘์„ฑํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.
  • sagas๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์•ก์…˜ ์ œ์ž‘์ž๋Š” ๋Œ€๋ถ€๋ถ„ ์ผ๋ฐ˜ ๊ฐ์ฒด ๋ฆฌํ„ฐ๋Ÿด์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ฝํฌ์˜ ์•ฝ์†๊ณผ ๋‹ฌ๋ฆฌ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์ฃผ์žฅํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค.

Sagas๋Š” ๋” ๊ฐ•๋ ฅํ•ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์ฝํฌ์˜ ์•ก์…˜ ์ œ์ž‘์ž์—์„œ ํ•  ์ˆ˜์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ ๋˜ํ•œ ํ•˜๋‚˜์˜ ์‚ฌ๊ฐ€์—์„œ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ทธ ๋ฐ˜๋Œ€๋Š” ์•„๋‹™๋‹ˆ๋‹ค (๋˜๋Š” ์ ์–ด๋„ ์‰ฝ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค). ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์•ก์…˜ / ์•ก์…˜์ด ํŒŒ๊ฒฌ ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค ( take)
  • ๋ฃจํ‹ด์„ ๊ธฐ์กด์˜ ์ทจ์†Œ ( cancel, takeLatest, race)
  • ์—ฌ๋Ÿฌ ๋ฃจํ‹ด์ด ๊ฐ™์€ ํ–‰๋™์„๋“ค์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ( take, takeEvery, โ€ฆ)

Sagas๋Š” ๋˜ํ•œ ๋ช‡ ๊ฐ€์ง€ ์ผ๋ฐ˜์ ์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํŒจํ„ด์„ ์ผ๋ฐ˜ํ™”ํ•˜๋Š” ๋‹ค๋ฅธ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

  • channels ์™ธ๋ถ€ ์ด๋ฒคํŠธ ์†Œ์Šค (์˜ˆ : ์›น ์†Œ์ผ“)๋ฅผ ์ฒญ์ทจ
  • ํฌํฌ ๋ชจ๋ธ ( fork, spawn)
  • ์กฐ์ ˆํŒ
  • โ€ฆ

Sagas๋Š” ์œ„๋Œ€ํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ถŒ๋ ฅ์—๋Š” ์ฑ…์ž„์ด ๋”ฐ๋ฅธ๋‹ค. ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด ์ปค์ง€๋ฉด ์ž‘์—…์ด ์ „๋‹ฌ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์‚ฌ๋žŒ ๋˜๋Š” ์ž‘์—…์ด ์ „๋‹ฌ ๋  ๋•Œ ๋ชจ๋“  ์ผ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ํŒŒ์•…ํ•˜์—ฌ ์‰ฝ๊ฒŒ ์†์‹ค ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— ์ฝ ํฌ๋Š” ๋” ๋‹จ์ˆœํ•˜๊ณ  ์ถ”๋ก ํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜ ๋˜๋Š” ๋‹ค๋ฅธ ๊ฒƒ์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์€ ํ”„๋กœ์ ํŠธ์˜ ์œ ํ˜• ๋ฐ ํฌ๊ธฐ, ํ”„๋กœ์ ํŠธ๊ฐ€ ํŒ€ ์„ ํ˜ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ๊ฐœ๋ฐœํ•ด์•ผํ•˜๋Š” ๋ถ€์ž‘์šฉ์˜ ์œ ํ˜•๊ณผ ๊ฐ™์€ ๋งŽ์€ ์ธก๋ฉด์— ๋‹ฌ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด์จŒ๋“  ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐ„๋‹จํ•˜๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ฒŒ ์œ ์ง€ํ•˜์‹ญ์‹œ์˜ค.


๋‹ต๋ณ€

๊ฐœ์ธ์ ์ธ ๊ฒฝํ—˜ :

  1. ์ฝ”๋”ฉ ์Šคํƒ€์ผ๊ณผ ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ๊ณผ๊ฑฐ์— redux-saga๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ํฐ ์žฅ์  ์ค‘ ํ•˜๋‚˜๋Š” redux-thunk์—์„œ ์ฝœ๋ฐฑ ์ง€์˜ฅ์„ ํ”ผํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋” ์ด์ƒ ์ค‘์ฒฉ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด์ œ async / await ์ฝํฌ๊ฐ€ ๋Œ€์ค‘ํ™”๋˜๋ฉด์„œ redux-thunk๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋™๊ธฐํ™” ์Šคํƒ€์ผ๋กœ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” redux-think์˜ ๊ฐœ์„ ์œผ๋กœ ๊ฐ„์ฃผ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  2. redux-saga๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, ํŠนํžˆ Typescript์—์„œ ํ›จ์”ฌ ๋” ๋งŽ์€ ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํŽ˜์น˜ ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ํ•˜๋‚˜์˜ ๋‹จ์ผ FETCH ์กฐ์น˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ action.js์—์„œ ํ•˜๋‚˜์˜ ์ฝํฌ ๋‹จ์œ„๋กœ ๋ฐ์ดํ„ฐ ๋ฐ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ์ง์ ‘ ์ˆ˜ํ–‰ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ redux-saga์—์„œ๋Š” FETCH_START, FETCH_SUCCESS ๋ฐ FETCH_FAILURE ์ž‘์—… ๋ฐ ๋ชจ๋“  ๊ด€๋ จ ์œ ํ˜• ๊ฒ€์‚ฌ๋ฅผ ์ •์˜ํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. redux-saga์˜ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๋Š” ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ํ’๋ถ€ํ•œ โ€œํ† ํฐโ€๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•˜์—ฌ ํšจ๊ณผ๋ฅผ ๋งŒ๋“ค๊ณ  ์ง€์‹œํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์‰ฌ์šด ํ…Œ์ŠคํŠธ๋ฅผ์œ„ํ•œ redux store. ๋ฌผ๋ก  ์ด๋Ÿฌํ•œ ํ–‰๋™์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‚ฌ๊ฐ€๋ฅผ ์“ธ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ๊ทธ๊ฒƒ์€ ์ฝํฌ์™€ ๋น„์Šทํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

  3. ํŒŒ์ผ ๊ตฌ์กฐ์˜ ๊ด€์ ์—์„œ, redux-saga๋Š” ๋งŽ์€ ๊ฒฝ์šฐ ๋” ๋ถ„๋ช…ํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  sagas.ts์—์„œ ๋น„๋™๊ธฐ ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ์ง€๋งŒ redux-thunk์—์„œ๋Š” ๋™์ž‘์—์„œ ์ฝ”๋“œ๋ฅผ ๋ณผ ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  4. ์‰ฌ์šด ํ…Œ์ŠคํŠธ๋Š” redux-saga์˜ ๋˜ ๋‹ค๋ฅธ ๊ฐ€์ค‘์น˜ ๊ธฐ๋Šฅ ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ •๋ง ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ redux-saga โ€œํ˜ธ์ถœโ€ํ…Œ์ŠคํŠธ๋Š” ํ…Œ์ŠคํŠธ์—์„œ ์‹ค์ œ API ํ˜ธ์ถœ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ API ํ˜ธ์ถœ ํ›„์— ์‚ฌ์šฉํ•  ์ˆ˜์žˆ๋Š” ๋‹จ๊ณ„์— ๋Œ€ํ•œ ์ƒ˜ํ”Œ ๊ฒฐ๊ณผ๋ฅผ ์ง€์ •ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ redux-saga๋กœ ์ž‘์„ฑํ•˜๊ธฐ ์ „์— saga ๋ฐ ํ•ด๋‹น sagas.spec.ts๋ฅผ ์ž์„ธํžˆ ๊ณ„ํšํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

  5. Redux-saga๋Š” ๋ณ‘๋ ฌ ์ž‘์—… ์‹คํ–‰, takeLatest / takeEvery, ํฌํฌ / ์Šคํฐ ๊ฐ™์€ ๋™์‹œ์„ฑ ๋„์šฐ๋ฏธ์™€ ๊ฐ™์€ ๋งŽ์€ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.์ด ๊ธฐ๋Šฅ์€ ์ฝํฌ๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ•๋ ฅํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๋ก ์ ์œผ๋กœ ๊ฐœ์ธ์ ์œผ๋กœ ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๋งŽ์€ ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ์™€ ์ค‘์†Œํ˜• ์•ฑ์—์„œ async / await ์Šคํƒ€์ผ redux-thunk์™€ ํ•จ๊ป˜ํ•˜์‹ญ์‹œ์˜ค. ๋งŽ์€ ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ / ์•ก์…˜ / ํƒ€์ž… ์ •์˜๋ฅผ ์ €์žฅํ•˜๊ณ  ์—ฌ๋Ÿฌ ๊ฐ€์ง€ sagas.ts๋ฅผ ์ „ํ™˜ํ•˜๊ณ  ํŠน์ • sagas ํŠธ๋ฆฌ๋ฅผ ์œ ์ง€ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งค์šฐ ๋ณต์žกํ•œ ๋น„๋™๊ธฐ ๋กœ์ง๊ณผ ๋™์‹œ์„ฑ / ๋ณ‘๋ ฌ ํŒจํ„ด๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ ๋Œ€ํ˜• ์•ฑ์„ ๊ฐœ๋ฐœํ•˜๊ฑฐ๋‚˜ ํ…Œ์ŠคํŠธ ๋ฐ ์œ ์ง€ ๊ด€๋ฆฌ (ํŠนํžˆ ํ…Œ์ŠคํŠธ ์ค‘์‹ฌ ๊ฐœ๋ฐœ)์— ๋Œ€ํ•œ ์ˆ˜์š”๊ฐ€ ๋†’์€ ๊ฒฝ์šฐ redux-sagas๋Š” ์ƒ๋ช…์„ ๊ตฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. .

์–ด์จŒ๋“  redux-saga๋Š” redux ์ž์ฒด๋ณด๋‹ค ์–ด๋ ต๊ณ  ๋ณต์žกํ•˜์ง€ ์•Š์œผ๋ฉฐ ํ•ต์‹ฌ ๊ฐœ๋…๊ณผ API๊ฐ€ ์ œํ•œ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์†Œ์œ„ ๊ฐ€ํŒŒ๋ฅธ ํ•™์Šต ๊ณก์„ ์ด ์—†์Šต๋‹ˆ๋‹ค. redux-saga๋ฅผ ๋ฐฐ์šฐ๋Š” ๋ฐ ์•ฝ๊ฐ„์˜ ์‹œ๊ฐ„์„ ํˆฌ์žํ•˜๋ฉด ์•ž์œผ๋กœ ์–ธ์  ๊ฐ€๋Š” ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋‹ต๋ณ€

๋‚ด ๊ฒฝํ—˜์—์„œ ๋ช‡ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๋Œ€๊ทœ๋ชจ React / Redux ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฒ€ํ†  ํ•œ Sagas๋Š” ๊ฐœ๋ฐœ์ž์—๊ฒŒ ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ๋” ์‰ฝ๊ณ  ์ž˜๋ชปํ•˜๊ธฐ ์–ด๋ ค์šด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š”๋ณด๋‹ค ์ฒด๊ณ„์ ์ธ ๋ฐฉ๋ฒ•์„ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ์‹œ์ž‘ํ•˜๊ธฐ์—๋Š” ์กฐ๊ธˆ ์–ด๋ฆฌ์„์ง€ ๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ๊ฐœ๋ฐœ์ž๋Š” ํ•˜๋ฃจ ๋งŒ์— ์ดํ•ดํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ํ•ญ์ƒ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋ฌด์—‡ yield์„ ์‹œ์ž‘ ํ•ด์•ผํ•˜๋Š”์ง€ ๊ฑฑ์ •ํ•˜์ง€ ๋ง๋ผ๊ณ  ๋งํ•˜๊ณ  ์ผ๋‹จ ํ…Œ์ŠคํŠธ๋ฅผ ๋‘ ๋ฒˆํ•˜๋ฉด ๋‹น์‹ ์—๊ฒŒ ์˜ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ฝํฌ๊ฐ€ MVC ํŒจํŠผ์˜ ์ปจํŠธ๋กค๋Ÿฌ ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์ทจ๊ธ‰๋˜๋Š” ๋ช‡ ๊ฐ€์ง€ ํ”„๋กœ์ ํŠธ๋ฅผ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋น ๋ฅด๊ฒŒ ๊ด€๋ฆฌ ํ•  ์ˆ˜์—†๋Š” ํ˜ผ๋ž€์ด๋ฉ๋‹ˆ๋‹ค.

๋‚ด ์กฐ์–ธ์€ A๊ฐ€ ๋‹จ์ผ ์ด๋ฒคํŠธ์™€ ๊ด€๋ จ๋œ B ์œ ํ˜• ๋ฌผ๊ฑด์„ ํŠธ๋ฆฌ๊ฑฐ ํ•ด์•ผํ•˜๋Š” ๊ณณ์—์„œ Sagas๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์กฐ์น˜๋ฅผ ์ทจํ•  ์ˆ˜์žˆ๋Š” ๊ฒƒ์€ ๊ณ ๊ฐ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ž‘์„ฑํ•˜๊ณ  FSA ์กฐ์น˜์˜ ๋ฉ”ํƒ€ ํŠน์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํŠธ๋ฆฌ๊ฑฐํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค.


๋‹ต๋ณ€

์ฝํฌ ๋Œ€ ์‚ฌ ๊ฐ€์Šค

Redux-Thunk๊ทธ๋ฆฌ๊ณ  Redux-Saga๋ช‡ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ๋‹ค๋ฅธ ๋‘ ๋Œ์•„ ์˜ค๋Š” ๋ฏธ๋“ค์›จ์–ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (๋Œ์•„ ์˜ค๋Š” ๋ฏธ๋“ค์›จ์–ด ์ฐจ๋‹จ ์กฐ์น˜๊ฐ€ ๋ฐœ์†ก () ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ €์žฅ์†Œ๋กœ ๋“ค์–ด์˜ค๋Š” ๊ฒƒ์„ ์ฝ”๋“œ)์ž…๋‹ˆ๋‹ค.

์•ก์…˜์€ ๋ง ๊ทธ๋Œ€๋กœ ์–ด๋–ค ๊ฒƒ์ด ๋“  ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋”ฐ๋ฅด๋Š” ๊ฒฝ์šฐ ์•ก์…˜์€ ์œ ํ˜• ํ•„๋“œ์™€ ์„ ํƒ์  ํŽ˜์ด๋กœ๋“œ, ๋ฉ”ํƒ€ ๋ฐ ์˜ค๋ฅ˜ ํ•„๋“œ๊ฐ€์žˆ๋Š” ์ผ๋ฐ˜ ์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. ์˜ˆ :

const loginRequest = {
    type: 'LOGIN_REQUEST',
    payload: {
        name: 'admin',
        password: '123',
    }, };

Redux-Thunk

Redux-Thunk๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ‘œ์ค€ ์กฐ์น˜ ๋””์ŠคํŒจ์น˜ ์™ธ์—๋„ ์ด๋ผ๋Š” ํŠน์ˆ˜ ํ•จ์ˆ˜๋ฅผ ๋””์ŠคํŒจ์น˜ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค thunks.

์ฝํฌ (Redux)๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค.

export const thunkName =
   parameters =>
        (dispatch, getState) => {
            // Your application logic goes here
        };

์ฆ‰, a thunk๋Š” ์„ ํƒ์ ์œผ๋กœ ์ผ๋ถ€ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๋‚ด๋ถ€ ํ•จ์ˆ˜๋Š” a dispatch function์™€ ํ•จ์ˆ˜๋ฅผ ์ทจํ•ฉ๋‹ˆ๋‹ค. getState๋‘˜ ๋‹ค Redux-Thunk๋ฏธ๋“ค์›จ์–ด์—์„œ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค .

๋ ˆ๋• ์‚ฌ๊ฐ€

Redux-Saga๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ณต์žกํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์„ sagas๋ผ๋Š” ์ˆœ์ˆ˜ํ•œ ํ•จ์ˆ˜๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ˆœ์ˆ˜ํ•œ ๊ธฐ๋Šฅ์€ ํ…Œ์ŠคํŠธ ๊ด€์ ์—์„œ ๋ฐ”๋žŒ์งํ•˜๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ณ  ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ๋น„๊ต์  ์‰ฝ์Šต๋‹ˆ๋‹ค.

Sagas๋Š” ๋ฐœ์ „๊ธฐ ๊ธฐ๋Šฅ์ด๋ผ๋Š” ํŠน์ˆ˜ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ๋“ค์€์˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค ES6 JavaScript. ๊ธฐ๋ณธ์ ์œผ๋กœ yield ๋ฌธ์„ ๋ณด๋Š” ๊ณณ๋งˆ๋‹ค ์‹คํ–‰์ด ์ƒ์„ฑ๊ธฐ ์•ˆํŒŽ์œผ๋กœ ์ ํ”„ํ•ฉ๋‹ˆ๋‹ค. yield๋ช…๋ น๋ฌธ์ด ์ƒ์„ฑ๊ธฐ๋ฅผ ์ผ์‹œ ์ค‘์ง€ํ•˜๊ณ  ์ƒ์„ฑ ๋œ ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ƒ๊ฐํ•˜์‹ญ์‹œ์˜ค . ๋‚˜์ค‘์— ํ˜ธ์ถœ์ž๋Š” ๋‹ค์Œ์— ๋‚˜์˜ค๋Š” ๋ฌธ์—์„œ ์ƒ์„ฑ๊ธฐ๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค yield.

์ƒ์„ฑ๊ธฐ ํ•จ์ˆ˜๋Š” ์ด์™€ ๊ฐ™์ด ์ •์˜๋ฉ๋‹ˆ๋‹ค. function ํ‚ค์›Œ๋“œ ๋‹ค์Œ์— ๋ณ„ํ‘œ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

function* mySaga() {
    // ...
}

์ผ๋‹จ ๋กœ๊ทธ์ธ ์‚ฌ๊ฐ€์ด ๋“ฑ๋ก๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค Redux-Saga. ๊ทธ๋Ÿฌ๋‚˜ yield์ฒซ ๋ฒˆ์งธ ์ค„์„ ๊ฐ€์ ธ ๊ฐ€๋ฉด ์œ ํ˜• 'LOGIN_REQUEST'์ด ์žˆ๋Š” ์ž‘์—… ์ด ์ƒ์ ์— ๋ฐœ์†ก ๋  ๋•Œ๊นŒ์ง€ ์‚ฌ๊ฐ€๋ฅผ ์ผ์‹œ ์ค‘์ง€ํ•ฉ๋‹ˆ๋‹ค . ๊ทธ๋ ‡๊ฒŒ๋˜๋ฉด ์‹คํ–‰์ด ๊ณ„์†๋ฉ๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ์€์ด ๊ธฐ์‚ฌ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค .


๋‹ต๋ณ€

ํ•˜๋‚˜์˜ ๋น ๋ฅธ ๋ฉ”๋ชจ. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋Š” ์ทจ์†Œ ๊ฐ€๋Šฅํ•˜๊ณ  ๋น„๋™๊ธฐ / ๋Œ€๊ธฐ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์งˆ๋ฌธ์˜ ์˜ˆ๋ฅผ ๋“ค์–ด, ์‹ค์ œ๋กœ ๋ฌด์—‡์„ ์„ ํƒ ํ•ด์•ผํ•˜๋Š”์ง€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋” ๋ณต์žกํ•œ ํ๋ฆ„์˜ ๊ฒฝ์šฐ ๋•Œ๋•Œ๋กœ ์ƒ์„ฑ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋‚˜์€ ์†”๋ฃจ์…˜์ด ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋˜ ๋‹ค๋ฅธ ์•„์ด๋””์–ด๋Š” redux-thunk๊ฐ€์žˆ๋Š” ๋ฐœ์ „๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ ๋‚˜์—๊ฒŒ๋Š” ์‚ฌ๊ฐ ๋ฐ”ํ€ด๊ฐ€ ๋‹ฌ๋ฆฐ ์ž์ „๊ฑฐ๋ฅผ ๋ฐœ๋ช…ํ•˜๋ ค๊ณ ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก  ๋ฐœ์ „๊ธฐ๋Š” ํ…Œ์ŠคํŠธํ•˜๊ธฐ๊ฐ€ ๋” ์‰ฝ์Šต๋‹ˆ๋‹ค.


์ด ๊ธ€์€ Javascript ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ๋ถ„๋ฅ˜๋˜์—ˆ๊ณ  ๋‹˜์— ์˜ํ•ด ์— ์ž‘์„ฑ๋์Šต๋‹ˆ๋‹ค.