본문 바로가기

Dot Programming/React ∙ Next.js

[React/ Next.js] Redux-saga 설치 및 알아보기 (vs thunk / generator, effect)

     

    1. redux-thunk  vs redux-saga

    thunk는 리덕스에서 비동기 작업을 처리할 때 많이 사용한다. 아래와 같이 9줄정도 되는 코드로 1만5천개정도의 git Star를 받았다.

    function createThunkMiddleware(extraArgument) {
      return ({ dispatch, getState }) => (next) => (action) => {
        if (typeof action === 'function') {
          return action(dispatch, getState, extraArgument);
        }
    
        return next(action);
      };
    }
    
    const thunk = createThunkMiddleware();
    thunk.withExtraArgument = createThunkMiddleware;
    
    export default thunk;

     

     

    벨로퍼트님 블로그에 예제가 있으니 연습해보자.

     

    4. redux-thunk · GitBook

    4. redux-thunk 소개 redux-thunk는 리덕스에서 비동기 작업을 처리 할 때 가장 많이 사용하는 미들웨어입니다. 이 미들웨어를 사용하면 액션 객체가 아닌 함수를 디스패치 할 수 있습니다. redux-thunk는

    react.vlpt.us

     

    그러나 나는 redux-thunk보다는 saga가 더 순수함수로 많은 기능을 사용할 수 있다고 하여 Redux-saga를 이용해보려고한다.

     

    redux-thunk의 경우엔 함수를 디스패치 할 수 있게 해주는 미들웨어이고,

    redux-saga의 경우엔 액션을 모니터링하고 있다가 특정 액션이 발생하면 이에 따라 특정 작업을 하는 방식으로 사용한다.

    * 여기서 특정 작업이란, 특장 자바스크립트를 실행하는 것 일수도 있고, 다른 액션을 디스패치 하는 것 일수도 있고, 현재 상태를 불러오는 것 일수도 있다.

     

    redux-saga는 redux-thunk로 못하는 다양한 작업들을 처리 할 수 있다.

    예)

    1. 비동기 작업을 할 때 기존 요청을 취소 처리 할 수 있다 (개꿀)
    2. 특정 액션이 발생했을 때 이에 따라 다른 액션이 디스패치되게끔 하거나, 자바스크립트 코드를 실행 할 수 있다 (개꿀)
    3. 웹소켓을 사용하는 경우 Channel 이라는 기능을 사용하여 더욱 효율적으로 코드를 관리 할 수 있다 (참고)
    4. API 요청이 실패했을 때 재요청하는 작업을 할 수 있다 (개꿀)

     

     

    2. next.js에 Redux-saga 설치

    1. next.js에 redux-saga를 설치한다.

    $ npm i redux-saga

     

    2. 설치 다음에 추가로 next-redux-saga를 설치해야한다. 

    (check)

    $ npm i next-redux-saga 

     

     

    3. /store/configureStore.js

    import createSagaMiddleware from 'redux-saga';
    
    import rootSaga from '../sagas';
    
    
    const configureStore = () => {
    	//saga #1
        const sagaMiddleware = createSagaMiddleware();
        const middlewares = [sagaMiddleware, loggerMiddleware];
    
    	...
        
        const enhancer = process.env.NODE_ENV === 'production'
        ? compose(applyMiddleware(...middlewares))
        : composeWithDevTools(applyMiddleware(...middlewares))
    
        const store = createStore(reducer, enhancer);
    
    	//saga #2
        store.sagaTask = sagaMiddleware.run(rootSaga);
       
         ...
        return store;
    
    };
    
    const wrapper = createWrapper(configureStore, {
        debug: process.env.NODE_ENV === 'development'
    });
    
    export default wrapper;

     

    4. next 공통 레이아웃 /pages/_app.js 에도 withReduxSaga를 추가해준다 (hoc)

    import withReduxSaga from 'next-redux-saga';
    
    ...
    
    
    export default wrapper.withRedux(withReduxSaga(Nodebird));

     

    5. sagas폴더를 생성 후 index.js파일을 생성

     

     

    generator

    이 문법의 핵심 기능은 함수를 작성 할 때 함수를 특정 구간에 멈춰놓을 수도 있고, 원할 때 다시 돌아가게 할 수도 있다.

    그리고 결과값을 여러번 반환 할 수도 있다.

     

    함수 특정 구간에 멈추기 yield

    함수 특정 구간에 멈추기 yield

     

    yield로 함수 절대 멈추지 않게 하기 while(true) 

    함수 절대 멈추지 않게 하기 while(true) 

     

    while(true) > 보통 무한 반복 걸려서 프로그램 망가지는데 saga에서는 다르게 동작한다.

      → 특정 이벤트에 g.next()를 하게 되고 그 때 while문을 실행하게 하면 eventListener와 역할이 같다

     

    redux-saga 예시 (generator)

     

    10. redux-saga · GitBook

    10. redux-saga 소개 redux-saga는 redux-thunk 다음으로 가장 많이 사용되는 라이브러리입니다. redux-thunk의 경우엔 함수를 디스패치 할 수 있게 해주는 미들웨어였지요? redux-saga의 경우엔, 액션을 모니터

    react.vlpt.us

     

    3. redux-saga effect 알아보기

    effect 종류

    all, call, fork, put, take, takeEvery, takeLatest, throttle

    (참고)

     

    put

     dispatch로 생각하면 된다.

     

    takeEvery

    모든 액션에 대하여 동작한다. (비동기)

     

    takeLatest

    같은 종류의 액션이 여러 번 요청된다면 가장 마지막 액션에 대해서만 동작을 실행한다. 즉 이전 액션 요청이 끝나지 않았음에도 불구하고 같은 종류의 액션이 여러 번 요청된다면 이전 요청을 취소한다. 웹페이지에서 특정 버튼을 여러 번 클릭하는 경우에 사용한다고 생각하면 된다.

     

    take

    해당 액션이 dispatch 되면 제너레이터를 next 하는 이펙트이다.

     

    fork, call

    fork call 모두 함수를 실행시켜주는 이펙트이다. 두 가지는 다음과 같은 차이가 있다.

    → fork는 비동기 실행을 한다.

    → call은 동기 실행을 한다. 따라서 순서대로 함수를 실행해야하는 API 요청 같은 곳에 쓰인다.

     

    take, takeEvery, takeLatest

    function* watchLogin(){
        yield takeEvery('LOG_IN_REQUEST', logIn);
    }
    
    
    // while-take
    function* watchLogOut(){
    	while(true){
    	    yield take('LOG_OUT_REQUEST', logOut);
        }
    }
    
    function* watchAddPost(){
        yield takeLatest('ADD_POST_REQUEST', addPost);
    }

    take의 단점은 1회용이다.

    > while(true)사용하면 됨

     

    while문을 넣기 싫을 때는 ? takeEvery를 사용하면 된다.

    while-take는 동기적으로 동작하지만 takeEvery는 비동기로 동작한다.

     

    takeLatest는 실수로 클릭 2번했을 때 마지막 리퀘만 보내줌 

    > 하지만 백엔드에는 요청이 2번 되어있는 상태이기 때문에 새로고침하면 2번 한 것으로 적용됨

     

    throttle

    마지막 함수가 호출된 후 일정 시간이 지나기 전에 다시 호출되지 않도록 하는 것(특수한 경우에만 사용. 보통 takeLatest사용)

    //2초동안 1번의 요청만 가능한 effect 
    function* watchAddPost(){
        yield throttle('ADD_POST_REQUEST', addPost, 2000);
    }

    throttling vs Debouncing 알아보기

     

    (JavaScript) 쓰로틀링과 디바운싱

    안녕하세요. 이번 시간에는 쓰로틀링(throttling)과 디바운싱(debouncing)에 대해 알아보겠습니다. 원래 예정에 없던 강좌이지만 요청을 받았기 때문에 써봅니다. 프로그래밍 기법 중 하나입니다(아니

    www.zerocho.com

     

    delay

    정해놓은 시간동안 비동기적인 효과를 줌

    function* logIn(action){
        try{
            yield delay(1000);
            // const result = yield call(logInAPI, action.data);
            yield put({
                type: 'LOG_IN_SUCCESS',
                // data: result.data
            });
        }
        catch(err){
            yield put({
                type: 'LOG_IN_FAILURE',
                data: err.response.data,
            })
        }
    }
    

     

     


    ※ 참고 목록

    벨로퍼트님 블로그 Redux-saga, Redux-thunk

    인프런 React-Nodebird