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

챠챠_님의 프로필 이미지
챠챠_

작성한 질문수

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

게시글 삭제 saga 작성하기

redux toolkit, saga으로 하는중에 devtool에서 액션 명칭이 undefined로 나옵니다

작성

·

185

0

안녕하세요 제로초님

여쭤보고 싶은게 있습니다.

강의를 따라가다가 데브툴에서 액션, 데이터들을 확인하시는 모습을 봤는데,

저도 따라해보니 액션명칭도, state tree의 데이터들도 제대로 안나오는것 같더라구요.

그래서 좀 테스트해보니까

아래의 로직처럼
put에 액션 함수를 실행하면 데브툴에서 액션 명칭니 나오고예시: put(액션명(데이터)),
기존처럼

put({type: 액션명, payload: 데이터}) 호출하게되면
undefined로 나오는것 같습니다.

function* addPost(action) {
   try {
	yield delay(1000);
	const id = shortid.generate();
	yield put(addPostSuccessAction({
				id,
				content: action.payload.text,
			})
		);
		yield put({ type: addPostToMe, payload: id });
	} catch (err) {
		yield put({ type: addPostFailureAction, error: err.response.data });
	}
}

아무래도 toolkit과 saga를 사용할때 저렇게 사용하는게 아닌가 싶은데
undefined로 나오는 부분은 개선했다고 하더라도

action 부분이 제로초님과 다르게 나오더라구요.

액션명만 나오는게 아니라 reducer의 위치도 함께나온느데

이렇게 나와도 괜찮은건지 여쭙고 싶습니다.

다른 부분은 잘 작동하는것 같습니다.

 

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

export const initialState = {
	mainPosts: [
		{
			id: "1",
			User: {
				id: "1",
				nickname: "zzimzzim",
			},
			content: "첫 번째 게시글 #해시태그, #익스프레스",
			Images: [
				{
					id: shortId.generate(),
					src: "https://loremflickr.com/cache/resized/65535_53669042936_630c778818_320_240_nofilter.jpg",
				},
				{
					id: shortId.generate(),
					src: "https://loremflickr.com/cache/resized/65535_52982053835_12fc661207_320_240_nofilter.jpg",
				},
				{
					id: shortId.generate(),
					src: "https://loremflickr.com/cache/resized/65535_52905479084_303bf25ec0_320_240_nofilter.jpg",
				},
			],
			Comments: [
				{
					id: shortId.generate(),
					User: {
						nickname: "찜찜",
					},
					content: "얼른 사고싶어요~",
				},
				{
					id: shortId.generate(),
					User: {
						nickname: "hero",
					},
					content: "리액트 넥스트 고수가 될테다~",
				},
			],
			createdAt: {},
		},
	],
	imagePaths: [],
	addPostLoading: false,
	addPostDone: false,
	addPostError: null,
	addCommentLoading: false,
	addCommentDone: false,
	addCommentError: null,
};

const dummyPost = ({ id, content }) => {
	return {
		id,
		content,
		User: {
			id: "1",
			nickname: "WlaWla",
		},
		Images: [],
		Comments: [],
	};
};

const dummyComment = (content) => ({
	id: shortId.generate(),
	content: content,
	User: {
		id: "1",
		nickname: "WlaWla",
	},
});

const postSlice = createSlice({
	name: "post",
	initialState,
	reducers: {
		addPostRequestAction: (state, action) => {
			state.addPostLoading = true;
			state.addPostDone = false;
			state.addPostError = null;
		},
		addPostSuccessAction: (state, action) => {
			state.addPostLoading = false;
			state.addPostDone = true;
			state.mainPosts.unshift(dummyPost(action.payload));
		},
		addPostFailureAction: (state, action) => {
			state.addPostLoading = false;
			state.addPostError = action.error;
		},
		addCommentRequestAction: (state, action) => {
			state.addCommentLoading = true;
			state.addCommentDone = false;
			state.addCommentError = null;
		},
		addCommentSuccessAction: (state, action) => {
			const { content, userId, postId } = action.payload;
			const post = state.mainPosts.find((d) => d.id === postId);
			post.Comments.unshift(dummyComment(content));
			state.addCommentLoading = false;
			state.addCommentDone = true;
		},
		addCommentFailureAction: (state, action) => {
			state.addCommentLoading = false;
			state.addCommentError = action.error;
		},
	},
	extraReducers: (builder) =>
		builder
			.addCase(HYDRATE, (state, action) => ({
				...state,
				...action.payload.post,
			}))
			.addDefaultCase((state) => state),
});

export const { addPostRequestAction, addPostSuccessAction, addPostFailureAction, addCommentRequestAction, addCommentSuccessAction, addCommentFailureAction } = postSlice.actions;
export default postSlice.reducer;

사가 코드입니다.

import { all, fork, delay, put, takeLatest } from "redux-saga/effects";
import axios from "axios";
import { addPostRequestAction, addPostSuccessAction, addPostFailureAction, addCommentRequestAction, addCommentSuccessAction, addCommentFailureAction } from "../reducers/post";
import { addPostToMe, removePostOfMe } from "../reducers/user";
import shortid from "shortid";

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

function* addPost(action) {
	try {
		// const result = yield call(addPostAPI, action.data);
		console.log("addPost saga", action);
		yield delay(1000);
		const id = shortid.generate();
		yield put(
			addPostSuccessAction({
				id,
				content: action.payload.text,
			})
		);
		yield put({ type: addPostToMe, payload: id });
	} catch (err) {
		yield put({ type: addPostFailureAction, error: err.response.data });
	}
}

function addCommentApi(data) {
	return axios.post(`/api/post/${data.postId}/comment`);
}
function* addComment(action) {
	try {
		// const result = yield call(addPostAPI, action.data);
		console.log("addComment saga", action);
		yield delay(1000);
		yield put({
			type: addCommentSuccessAction,
			payload: action.payload,
		});
	} catch (err) {
		console.log(err);
		yield put({
			type: addCommentFailureAction,
			error: err.response.data,
		});
	}
}

function* watchAddPost() {
	yield takeLatest(addPostRequestAction, addPost);
}

function* watchAddComment() {
	yield takeLatest(addCommentRequestAction, addComment);
}

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

답변 2

1

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

ai 인턴의 말 그대로입니다.

여기서는 yield put({ type: addPostToMe, payload: id });에서 addPostToMe가 액션 타입 문자열이 아닌 액션 생성 함수라면 액션 타입이 undefined로 나올 수 있습니다.

addPostToMe는 함수이지 액션 이름 문자열이 아닙니다.

1

안녕하세요, 인프런 AI 인턴입니다. 챠챠_님의 질문에 대해 답변 드립니다.

Redux Toolkit 및 Redux-Saga 사용 시 발생하는 액션명 undefined 문제와 관련하여, 코드 예시를 기준으로 문제점과 해결 방안을 알려드립니다.

문제의 핵심은 Redux-Saga에서 put 함수를 사용할 때 액션 생성함수를 직접 호출하는 형식과 put({type: 액션타입 문자열, payload: 데이터}) 형식 사이의 차이입니다. Redux Toolkit을 사용하면 액션 생성함수가 자동으로 생성되기 때문에, 직접 {type: ...} 형식을 사용하지 않고 생성된 액션 함수를 사용하는 것이 일반적입니다.

직접 관련된 문제 해결:

코드 내에서 yield put(addPostSuccessAction(...)) 형태로 액션 생성 함수를 호출하는 것은 정상적인 방식입니다. Saga에서 yield put({type: 액션타입, ...}) 형태로 사용할 때 액션타입undefined로 나오는 문제는, 액션타입을 정의할 때 문자열을 제대로 지정하지 않았거나 액션 생성 함수를 잘못 호출하는 경우 발생할 수 있습니다. 여기서는 yield put({ type: addPostToMe, payload: id });에서 addPostToMe가 액션 타입 문자열이 아닌 액션 생성 함수라면 액션 타입이 undefined로 나올 수 있습니다.
따라서, 올바른 액션 타입 문자열을 사용하거나 액션 생성 함수가 올바르게 반환하는지 확인해야 합니다.

그 외 Redux DevTools 관련 언급:

액션명 외에 리듀서의 위치가 함께 나오는 것은 Redux DevTools의 기능 중 하나로, 애플리케이션의 상태 관리가 어떻게 이루어지는지 더 상세하게 보여줍니다. 이는 디버깅 시 도움이 될 수 있으며, 일반적으로 문제가 되지 않습니다.

질문에 대한 추가적인 답변이 필요한 부분은 [리뉴얼] React로 NodeBird SNS 만들기 강의의 “saga의 addPost에서 addPostAPI를 못불러와요…” 질의응답 세션에서 더 찾아볼 수 있습니다. 여기서는 비슷한 문제 상황인 액션명이 undefined로 나오는 문제에 대한 조언을 찾을 수 있을 것입니다. 특히, saga에서 put을 사용함에 있어서 필요한 디버깅 방법에 대한 힌트를 얻을 수 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

챠챠_님의 프로필 이미지
챠챠_

작성한 질문수

질문하기