인프런 커뮤니티 질문&답변

hoze12님의 프로필 이미지
hoze12

작성한 질문수

[리뉴얼] React로 NodeBird SNS 만들기

saga 쪼개고 reducer와 연결하기

로그인시 LOG_IN_REQUEST 부분

해결된 질문

작성

·

349

0

이와 비슷한 문제가 많아서 참고해서
복붙도 해보면서 했는데도 해결되지 않아
질문 남깁니다.

로그인 버튼을 누르면 리덕스 데브툴에이와 같이 나오고 saga가 연결이 되지 않는 거 같아요

(코드 첨부)

sagas/index.js

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

// import postSaga from './post';
import userSaga from './user';

export default function* rootSaga() {
  console.log('rootSaga')
  yield all([
    fork(userSaga),
    // fork(postSaga),
  ]);
}

 

sagas/user.js

import { all } from "axios";
import { delay, fork, put, takeLatest } from "redux-saga/effects";
import { LOG_IN_FAILURE, LOG_IN_REQUEST, LOG_IN_SUCCESS, LOG_OUT_FAILURE, LOG_OUT_REQUEST, LOG_OUT_SUCCESS } from "../reducers/user";

// function logInApi(data) {
//   // 비동기 처리 함수는 일반함수로 정의
//   return axios.post("api/login", data);
// }

// function logOutApi() {
//   // 비동기 처리 함수는 일반함수로 정의
//   return axios.post("api/login");
// }

function* logIn(action) {
  console.log('login')
  try {
    console.log('saga logIn');
    // const result = yield call(logInApi, action.data); //요청의 결과
    yield delay(1000);
    yield put({
      type: LOG_IN_SUCCESS,
      data: action.data,
    });
  } catch (err) {
    console.error(err);
    yield put({
      type: LOG_IN_FAILURE,
      data: err.response.data,
    });
  }
}

function* logOut() {
  console.log('login')
  try {
    // const result = yield call(logOutApi); //요청의 결과
    yield delay(1000);
    yield put({
      type: LOG_OUT_SUCCESS,
    });
  } catch (err) {
    console.error(err);
    yield put({
      type: LOG_OUT_FAILURE,
      data: err.response.data,
    });
  }
}
function* watchLogIn() {
    console.log('watchLogIn')
  yield takeLatest(LOG_IN_REQUEST, logIn);
}

function* watchLogOUT() {
    console.log('watchLogOUT')
  yield takeLatest(LOG_OUT_REQUEST, logOut);
}

export default function* userSaga() {
  yield all([
    fork(watchLogIn),
    fork(watchLogOUT)
  ])
}

const g = watchLogIn();
console.log(g.next())


sagas/posts.js

 

import { all } from "axios";
import { delay, fork, put, takeEvery } from "redux-saga/effects";

// function addPostsApi(data) {
//   // 비동기 처리 함수는 일반함수로 정의
//   return axios.post("api/login", data);
// }

function* addPosts(action) {
  console.log('addPosts')
  try {
    // const result = yield call(addPostsApi, action.data); //요청의 결과
    yield delay(1000);
    yield put({
      type: "ADD_POST_SUCESS",
      data: action.data,
    });
  } catch (err) {
    yield put({
      type: "ADD_POST_FAILURE",
      data: err.response.data,
    });
  }
}

function* watchAddPost() {
  yield takeEvery("ADD_POST_REQUEST", addPosts);
}

export default function* postSaga() {
  yield all([fork(watchAddPost)]);
}

 

reducers/index.js

import { HYDRATE } from "next-redux-wrapper";
import { combineReducers } from "redux";
import user from "./user";
import post from "./post";

// (이전 상태, 액션) => 다음 상태
const rootReducer = combineReducers({
  index: (state = {}, action) => {
    switch (action.type) {
      case HYDRATE:
        console.log("HYDRATE", action);
        return { ...state, ...action.payload };
      default:
        return state;
    }
  },
  user,
  post,
});

export default rootReducer;

 

reducers/user.js

export const initialState = {
  isLoggingIn: false, //로그인 시도(로딩)중
  isLoggedIn: false, // 로그인된 상태
  isLoggingOut: false, // 로그아웃 시도(로딩)중 
  me: null, //내정보
  signUpData: {},
  loginData: {},
};

export const LOG_IN_REQUEST = 'LOG_IN_REQUEST';
export const LOG_IN_SUCCESS = 'LOG_IN_SUCCESS';
export const LOG_IN_FAILURE = 'LOG_IN_FAILURE';

export const LOG_OUT_REQUEST = 'LOG_OUT_REQUEST';
export const LOG_OUT_SUCCESS = 'LOG_OUT_SUCCESS';
export const LOG_OUT_FAILURE = 'LOG_OUT_FAILURE';


export const loginRequestAction = (data) => ({
  type: LOG_IN_REQUEST,
  data
});      

export const logOutRequestAction = () => ({
  type: LOG_OUT_REQUEST,
});

const user = (state = initialState, action) => {
  switch (action.type) {
    case LOG_IN_REQUEST:
      console.log('reducer login')
      return {
        ...state,
        isLoggingIn: true,
      };
    case LOG_IN_SUCCESS:
      return {
        ...state,
        isLoggingIn: false,
        isLoggedIn: true,
        me: {...action.data, nickname: 'skylove1004'},
      };
    case LOG_IN_FAILURE:
      return {
        ...state,
        isLoggingIn: false,
        isLoggedIn: false,
      };
    case LOG_OUT_REQUEST:
      return {
        ...state,
        isLoggingOut: true,
      };
    case LOG_OUT_SUCCESS:
      return {
        ...state,
        isLoggingOut: false,
        isLoggedIn: false,
        me: null,
      };
    case LOG_OUT_FAILURE:
      return {
        ...state,
        isLoggingOut: false,
      };
    default:
      return state;
  }
};

export const userState = (state) => state.user;
export default user;

reducers/post.js

export const initialState = {
  mainPosts: [
    {
      id: 1,
      User: {
        id: 1,
        nickname: "skyblue5030",
      },
      content: "첫 번째 게시글 #express #react",
      Images: [
        {
          src: "https://bookthumb-phinf.pstatic.net/cover/137/995/13799585.jpg?udate=20180726",
        },
        {
          src: "https://gimg.gilbut.co.kr/book/BN001958/rn_view_BN001958.jpg",
        },
        {
          src: "https://gimg.gilbut.co.kr/book/BN001998/rn_view_BN001998.jpg",
        },
      ],
      Comments: [
        {
          User: {
            nickname: "nero",
          },
          content: "우와 개정판이 나왔군요~",
        },
        {
          User: {
            nickname: "hero",
          },
          content: "얼른 사고싶어요~",
        },
      ],
    },
  ],
  imagePaths: [], //이미지업로드시 추가됨
  postAdded: false,
};

const ADD_POST = "ADD_POST";
export const addPost = {
  type: ADD_POST,
};

const dummyPost = {
  id: 2,
  content: "더미데이터입니다.",
  User: {
    id: 1,
    nickname: "제로초",
  },
  Images: [],
  Comments: [],
};
// 데이터를 먼저 구성, 화면은 작성한 데이터나 데이터 변경을 기준으로 구성
// 데이터 구조는 서버측과 합의해서 구성해야 나중에 수정할 일이 없음
const post = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_POST_SUCCESS':
      return {
        ...state,
        mainPosts: [dummyPost, ...state.mainPosts],
        // 데이터을 앞에 추가해서 게시글이 위로 올라가게 
        postAdded: true,
      };
    default:
      return state;
  }
};

export const postState = (state) => state.post;
export default post;

 

store/configureStore.js

 

import { applyMiddleware, compose, createStore } from "redux";
import createSagaMiddleware from "redux-saga";
import { createWrapper } from "next-redux-wrapper";
import { composeWithDevTools } from "redux-devtools-extension";

import reducer from "../reducers";
import rootSaga from "../sagas";

const loggerMidddleware =
  ({ getState }) =>
  (next) =>
  (action) => {
    console.log({ action, getState });
    return next(action);
  };

const configureStore = () => {
  const sagaMiddleware = createSagaMiddleware();
  const middlewares = [sagaMiddleware, loggerMidddleware];
  const enhancer =
    process.env.NODE_ENV === "production"
      ? compose(applyMiddleware(...middlewares))
      : composeWithDevTools(applyMiddleware(...middlewares));
  const store = createStore(reducer, enhancer);
  store.sagaTask = sagaMiddleware.run(rootSaga);
  return store;
};

const wrapper = createWrapper(configureStore, {
  debug: process.env.NODE_ENV === "development",
});

export default wrapper;


답변 1

0

hoze12님의 프로필 이미지
hoze12
질문자

해결 했습니다.
역시 import를 잘못해서....
자동완성으로 import 불러와도
확인을 한번 해야겠군요 ㅠㅠ

sagas/user.js 란 폴더에
all을 불러올 때 axios로 불러왔더군요
부끄럽습니당

ch4 코드 완성본을 보며
한줄 씩 지워가며 찾았습니다
오타주의 import 주의

hoze12님의 프로필 이미지
hoze12

작성한 질문수

질문하기