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

챠챠_님의 프로필 이미지

작성한 질문수

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

saga 쪼개고 reducer와 연결하기

toolkit, saga를 사용하는데 saga에서 로그인정보 받을때 state가 이전 state가 아니라 proxy데이터가 나옵니다.

작성

·

193

0

안녕하세요 제로초님

toolkit, saga를 사용하는데 saga에서 로그인정보 받을때 state가 이전 state가 아니라 proxy데이터가 나옵니다.

 

saga에서 이런식으로 호출을 해주면

action 데이터도 잘 찍힙니다.

function* login(action) {
	try {
		console.log("saga login");
		console.log(action);
		// const result = yield call(loginAPI, action.data);
		yield delay(1000);
		yield put({
			type: loginSuccessAction,
			payload: action.payload,
		});
	} catch (err) {
		yield put({
			type: loginFailureAction,
			// data: err.response.data,
		});
	}
}

그다음 리듀서에서
const userSlice = createSlice({ name: "user", initialState, reducers: { logIn: (state, action) => { state.isLoggedIn = true; state.me = action.payload; }, logOut: (state) => { state.isLoggedIn = false; state.me = null; }, loginRequestAction: (state) => { console.log("state", state); state.isLoggingIn = true; }, loginSuccessAction: (state, action) => { console.log("reducer login"); console.log("state", state); state.isLoggingIn = false; state.isLoggedIn = false; state.me = action.payload; state.me.nickname = "zzimzzim"; }, loginFailureAction: (state) => { state.isLoggingIn = false; state.isLoggedIn = false; }, logoutRequestAction: (state) => { state.isLoggingOut = true; }, logoutSuccessAction: (state) => { state.isLoggingOut = false; state.isLoggedIn = false; state.me = null; }, logoutFailureAction: (state) => { state.isLoggingOut = false; }, }, extraReducers: (builder) => builder .addCase(HYDRATE, (state, action) => ({ ...state, ...action.payload.user, })) .addDefaultCase((state) => state), });

 

위와같이 코드를 만들고

로그인을 해보면

action으로 로그인 정보를 잘 내려줍니다.

원래는 이전의 state (현 store데이터)를 받아오고

거기서 action데이터를 넣어서 업데이트해줘야하는데,

state에서 proxy데이터가 내려와서 업데이트가 안되고 있습니다. ㅠ

 

리듀서에서 action 데이터 받고, state호출했을때,

  1. Proxy(Object) {type_: 0, scope_: {…}, modified_: false, finalized_: false, assigned_: {…}, …}

    1. [[Handler]]: null

    2. [[Target]]: null

    3. [[IsRevoked]]: true

이러한 경우에 reducer에서 state를 받아오는 방법이 있을까요? 혹시 코드가 이상하거나 틀렸다면 지적해주시면 감사하겠습니다.

답변 2

0

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

코드 포매팅좀 해주세요. 툴킷을 쓸 때는 프록시 객체가 나오는 게 맞습니다.

챠챠_님의 프로필 이미지
챠챠_
질문자

/sagas/user.js

import { all, fork, delay, put, takeLatest } from "redux-saga/effects";
import axios from "axios";
import {
	loginRequestAction,
	loginFailureAction,
	loginSuccessAction,
	logoutFailureAction,
	logoutRequestAction,
	logoutSuccessAction,
} from "../reducers/user";

function loginAPI(data) {
	return axios.post("/api/login", data);
}

function* login(action) {
	try {
		yield delay(1000);
		yield put(loginSuccessAction(action.payload));
	} catch (err) {
		yield put({
			type: loginFailureAction,
			// data: err.response.data,
		});
	}
}

function logoutAPI() {
	return axios.post("/api/logout");
}

function* logout() {
	try {
		// const result = yield call(logoutAPI);
		yield delay(1000);
		yield put({
			type: logoutSuccessAction,
			// data: result.data,
		});
	} catch (err) {
		yield put({
			type: logoutFailureAction,
			data: err.response.data,
		});
	}
}

function* watchLogIn() {
	yield takeLatest(loginRequestAction, login);
}

function* watchLogOut() {
	yield takeLatest(logoutRequestAction, logout);
}

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

 

/reducers/user.js

import { createSlice, current } from "@reduxjs/toolkit";
import { HYDRATE } from "next-redux-wrapper";

const initialState = {
	isLoggingIn: false, // 로그인 시도중
	isLoggingOut: false, // 로그아웃 시도중
	isLoggedIn: false,
	me: null,
	signUpData: {},
	loginData: {},
};

const userSlice = createSlice({
	name: "user",
	initialState,
	reducers: {
		logIn: (state, action) => {
			state.isLoggedIn = true;
			state.me = action.payload;
		},
		logOut: (state) => {
			state.isLoggedIn = false;
			state.me = null;
		},
		loginRequestAction: (state) => {
			// console.log("reducer loginRequestAction");
			// console.log("state", state);
			state.isLoggingIn = true;
		},
		loginSuccessAction: (state, action) => {
			console.log("reducer login");
			console.log("state", state);
			
			console.log(action);

			state.isLoggingIn = false;
			state.isLoggedIn = true;
			state.me = action.payload;
			state.me.nickname = "zzimzzim";
		},
		loginFailureAction: (state) => {
			state.isLoggingIn = false;
			state.isLoggedIn = false;
		},
		logoutRequestAction: (state) => {
			state.isLoggingOut = true;
		},
		logoutSuccessAction: (state) => {
			state.isLoggingOut = false;
			state.isLoggedIn = false;
			state.me = null;
		},
		logoutFailureAction: (state) => {
			state.isLoggingOut = false;
		},
	},
	extraReducers: (builder) =>
		builder
			.addCase(HYDRATE, (state, action) => ({
				...state,
				...action.payload.user,
			}))
			.addDefaultCase((state) => state),
}); 

export const {
	logIn,
	logOut,
	loginRequestAction,
	loginSuccessAction,
	loginFailureAction,
	logoutRequestAction,
	logoutSuccessAction,
	logoutFailureAction,
} = userSlice.actions; // 액션 생성 함수

export default userSlice.reducer; // 리듀서

로그인할 때

const onFinish = useCallback((data) => {
		dispatch(loginRequestAction({ id: data.userId, password: data.password }));
	}, []);

주 코드는 위와 같습니다!

챠챠_님의 프로필 이미지
챠챠_
질문자

아.. 이상하네요 어제 몇번이나 시도했었는데

데이터를 못받아오더니 컴터 껐다키고 다른거하다가 다시 테스트해보니까 function* login(action)

{
	try {
		console.log("saga login---------------------------------");
		console.log("action", action);
		// const result = yield call(loginAPI, action.data);
		yield delay(1000);
		yield put({
			type: loginSuccessAction,
			payload: action.payload,
		});
	} catch (err) {
		yield put({
			type: loginFailureAction,
			// data: err.response.data,
		});
	}
}

이렇게 해도 데이터를 잘 받고,

로그인도 잘 됩니다.

귀신이곡할노릇이군요...

제가 무엇을 잘못했을텐데 그걸 몰라 답답한데 그래도 잘 되서 다행입니다. 감사합니다.!

제로초(조현영)님의 프로필 이미지
제로초(조현영)
지식공유자

put type에 action함수 자체를 넣어도 되는건 처음보네요. saga put이 지원하는 특수기능일지도 모르겠습니다.

0

챠챠_님의 프로필 이미지
챠챠_
질문자

껐다 켰다 검색해보니function* login(action) { try { // console.log("saga login"); // console.log(action); // const result = yield call(loginAPI, action.data); yield delay(1000); yield put(loginSuccessAction(action.payload)); } catch (err) { yield put({ type: loginFailureAction, // data: err.response.data, }); } }

이런식으로

호출해주면 잘 되는것 같습니다.
loginSuccessAction(action.payload)

reducer에서는 데이터 받을때 proxy로 보여도 되는것 같습니다.

후 쉽지않네요. 혹시나 틀렸거나 수정할거있으면 알려주시면 감사하겠습니다 ; D

챠챠_님의 프로필 이미지

작성한 질문수

질문하기