[Error] [React] [Redux-Saga] saga 무한히 실행

Yujin Bae·2021년 12월 21일
0

Error

https://github.com/mong-head/error/blob/master/images/saga_infinite_loop_problem.PNG?raw=true

  • 문제
    • 상황 : mount하는 시점에 dispatch실행
    • mount, action은 한번씩만 불렸지만, reducer과 saga는 여러번 호출됨
  • 관련 코드
    • Component (Layout.js)
      import React, {Component} from 'react';
      import { connect } from 'react-redux';
      import '../assets/css/Contacts.css';
      import {selectedContactAction} from '../Store/Actions/selectedContactAction'
      import {setContacts} from '../Store/Sagas/contactsSaga';
      
      class Layout extends Component {
      
          async componentDidMount() {
              this.props.setContacts();
          }
      
          render() {
            
              return (
                  <div className={'contacts'}>
      		          {
      									this.props.contacts
      							}  
                  </div>
              );
          }
      }
      
      const mapStateToProps = (state) => ({
          contacts : state.contacts
      });
      
      const mapDispatchToProps = (Dispatch) => {
          return {
              setContacts : () => Dispatch(contactsSetAction())
          }
      }
      
      export default connect(mapStateToProps,mapDispatchToProps)(Layout);
    • Action Types (types.js)
      export const contactsType = {
          CONTACTS_SET : 'CONTACTS_SET'
      }
    • Action (contactsAction.js)
      export const contactsSetAction = () => {
          return { type: contactsType.CONTACTS_SET }
      };
    • Saga (contactsSaga.js)
      export function* setContacts(){
          try{
              const response = yield call(fetchApi().getAll);
              yield put({type: contactsType.CONTACTS_SET, contacts : response.map(symbolizeObjectId)});
          } catch (error) {
              yield put({type: contactsType.CONTACTS_SET, contacts : {}})
          } finally {
          }
      }
      
      const saga = [
          takeLatest(contactsType.CONTACTS_SET, contactsSaga.setContacts),
      ]
      export default saga;
    • Reducer (contactReducer.js)
      import { contactsType } from '../Actions/types';
      
      const contactsReducer = (state = [], action) => {
          switch (action.type) {
              case contactsType.CONTACTS_SET:
                  return action.contacts ? action.contacts : state;
              default:
                  return state;
          }
      };
      
      export default contactsReducer;

Solve

https://github.com/mong-head/error/blob/master/images/saga_infinite_loop_problem_solved.PNG?raw=true

  • Action, Saga 용 type과 reducer용 type을 나누기

    • Action, Saga 용 : CONTACTS_SET
    • reducer 용 : CONTACTS_SET_RESULT
  • 변경한 코드 (CONTACTS_SET_RESULT 추가)

    • Action Types (types.js)
      export const contactsType = {
          CONTACTS_SET : 'CONTACTS_SET', //action, saga용
          CONTACTS_SET_RESULT : 'CONTACTS_SET_RESULT' // reducer 용
      }
    • Saga (contactsSaga.js)
      export function* setContacts(){
          try{
              const response = yield call(fetchApi().getAll);
              yield put({type: contactsType.CONTACTS_SET_RESULT, contacts : response.map(symbolizeObjectId)});
          } catch (error) {
              yield put({type: contactsType.CONTACTS_SET_RESULT, contacts : {}})
          } finally {
          }
      }
      
      const saga = [
          takeLatest(contactsType.CONTACTS_SET, contactsSaga.setContacts),
      ]
      export default saga;
    • Reducer (contactReducer.js)
      import { contactsType } from '../Actions/types';
      
      const contactsReducer = (state = [], action) => {
          switch (action.type) {
              case contactsType.CONTACTS_SET_RESULT:
                  return action.contacts ? action.contacts : state;
              default:
                  return state;
          }
      };
      
      export default contactsReducer;

핵심

무한히 saga를 호출하지 않게 하기 위해서 takeLatest에서 지켜보는 type과 put하는 type를 같게 하면 안된다.

  • error 주요 코드
    export function* setContacts(){
        try{
            const response = yield call(fetchApi().getAll);
            yield put({type: contactsType.CONTACTS_SET, contacts : response.map(symbolizeObjectId)});
        } catch (error) {
            yield put({type: contactsType.CONTACTS_SET, contacts : {}})
        } finally {
        }
    }
    
    // Action이랑 Saga 연결
    const saga = [
        takeLatest(contactsType.CONTACTS_SET, contactsSaga.setContacts)
    ];
    export default saga;
    • puttakeLatest type 같음
  • good 주요 코드
    export function* setContacts(){
        try{
            const response = yield call(fetchApi().getAll);
            yield put({type: contactsType.CONTACTS_SET_RESULT, contacts : response.map(symbolizeObjectId)});
        } catch (error) {
            yield put({type: contactsType.CONTACTS_SET_RESULT, contacts : {}})
        } finally {
        }
    }
    
    // Action이랑 Saga 연결
    const saga = [
        takeLatest(contactsType.CONTACTS_SET, contactsSaga.setContacts)
    ];
    export default saga;
    • puttakeLatest type 다름
profile
안녕하세요

0개의 댓글