강의

멘토링

로드맵

Inflearn brand logo image

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

bebe님의 프로필 이미지
bebe

작성한 질문수

Vue3 완벽 마스터: 기초부터 실전까지 - "실전편"

공통 컴포넌트 분리 (based on Vue.js 3 spec)

title,content값이 비어서 저장되는데 제가 혹시 어떤 부분을 잘못 작성했는지 ㅜㅜ 알고싶습니다.

작성

·

57

0

<template>
	<div>
		<h2>게시글 등록</h2>
		<hr class="my-4" />
		<PostForm
			v-model.title="form.title"
			v-model.content="form.content"
			@submit.prevent="savePost"
		>
			<template #actions>
				<div class="pt-4">
					<button
						type="button"
						class="btn btn-outline-dark me-2"
						@click="goPostListPage"
					>
						목록
					</button>
					<button class="btn btn-primary">저장</button>
				</div>
			</template>
		</PostForm>
		<!-- <form>
			<div class="mb-3">
				<label for="title" class="form-label">제목</label>
				<input
					v-model="form.title"
					type="text"
					class="form-control"
					id="title"
				/>
			</div>
			<div class="mb-3">
				<label for="content" class="form-label">내용</label>
				<textarea
					v-model="form.content"
					class="form-control"
					id="content"
					rows="3"
				></textarea>
			</div> -->
		<!-- <div class="pt-4">
				<button
					type="button"
					class="btn btn-outline-dark me-2"
					@click="goPostListPage"
				>
					목록
				</button>
				<button type="button" class="btn btn-primary" @click="goPostListPage">
					저장
				</button>
			</div> 
		</form>-->
	</div>
</template>

<script setup>
import { useRouter } from "vue-router";
import { createPost } from "@/api/posts";
import { ref } from "vue";

import PostForm from "@/components/posts/PostForm.vue";

const router = useRouter();

const form = ref({
	id: 0,
	title: "",
	content: "",
	createAt: Date.now(),
});

const savePost = () => {
	try {
		// const data = { ...form.value, createAt: Date.now() };
		createPost({ ...form.value });
		goPostListPage();
		// console.log("savePost data", data);
	} catch (err) {
		console.log("err", err);
	}
};

// 목록이동
const goPostListPage = () => {
	router.push({
		name: "PostList",
	});
};
</script>

<style lang="scss" scoped></style>
<template>
	<form>
		<div class="mb-3">
			<label for="title" class="form-label">제목</label>
			<!-- v-model을 사용하지 않고, v-bind와 @input 이벤트를 사용하여 양방향 데이터 바인딩 -->
			<input
				:value="title"
				@input="$emit('update:title', $event.target.value)"
				type="text"
				class="form-control"
				id="title"
			/>
		</div>
		<div class="mb-3">
			<label for="content" class="form-label">내용</label>
			<textarea
				:value="content"
				@input="$emit('update:content', $event.target.value)"
				class="form-control"
				id="content"
				rows="3"
			></textarea>
		</div>
		<!-- <div class="pt-4">
			<button
				type="button"
				class="btn btn-outline-dark me-2"
				@click="goPostListPage"
			>
				목록
			</button>
			<button type="button" class="btn btn-primary" @click="goPostListPage">
				저장
			</button>
		</div> -->
		<slot name="actions"></slot>
	</form>
</template>

<script setup>
defineProps({
	title: String,
	content: String,
});

// update:props데이터명
// 양방향 데이터 바인딩을 위해 사용 : 부모에게 내려받은 props를 업데이트
// update 접두사는 v-model과 함께 사용되는 이벤트 이름

defineEmits(["update:title", "update:content"]);
</script>

<style lang="scss" scoped></style>
{
  "posts": [
    {
      "id": 2,
      "title": "제목2",
      "content": "내용2",
      "createAt": "2021-01-02"
    },
    {
      "id": 3,
      "title": "제목3",
      "content": "내용3",
      "createAt": "2021-01-03"
    },
    {
      "id": 4,
      "title": "제목4",
      "content": "내용4",
      "createAt": "2021-01-04"
    },
    {
      "title": "제목8",
      "content": "내용83333333",
      "createAt": "2021-01-08",
      "id": 8
    },
    {
      "id": 9,
      "title": "",
      "content": "",
      "createAt": 1750817841654
    },
    {
      "id": 10,
      "title": "",
      "content": "",
      "createAt": 1750828553704
    }
  ]
}

title,content값이 비어서 저장되는데 제가 혹시 어떤 부분을 잘못 작성했는지 ㅜㅜ 알고싶습니다.


답변 3

0

짐코딩님의 프로필 이미지
짐코딩
지식공유자

v-model 구문에 오타가 있습니다

현재 코드 (잘못된 구문):

<PostForm
  v-model.title="form.title"      ← 잘못됨
  v-model.content="form.content"  ← 잘못됨
  @submit.prevent="savePost"
>

올바른 구문:

<PostForm
  v-model:title="form.title"      ← 콜론(:) 사용
  v-model:content="form.content"  ← 콜론(:) 사용
  @submit.prevent="savePost"
>

차이점

  • .(점): Vue 수식어 (modifier) - 예: v-model.lazy

  • :(콜론): props 바인딩 - 예: v-model:title

현재 상황:.title, .content를 수식어로 인식해서 실제 데이터 바인딩이 안 되고 있어서 빈 값으로 저장되는 겁니다.

PostForm.vue는 정상이고, 부모 컴포넌트에서 v-model 구문만 수정하면 해결됩니다.

0

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

짐코딩님 답변 기다릴게요.

0

안녕하세요, 인프런 AI 인턴입니다. bebe님.

제공하신 코드를 보면서 title과 content 값이 비어서 저장되는 문제를 진단해보겠습니다.

문제점 분석

  1. 양방향 바인딩 문제: PostForm 컴포넌트에서 부모 컴포넌트가 ref로 관리하는 form.titleform.content 값을 업데이트 해야 합니다. 그러나 현재 PostForm.vue에서는 v-model 대신 직접 이벤트를 통해 값을 업데이트하고 있습니다. 이 방식은 잘못 구현될 경우 데이터가 부모로 제대로 전달되지 않을 수 있습니다.

  2. v-model의 이벤트 사용: 현재 v-model을 통해 emit하는 이벤트는 update:titleupdate:content입니다. 이 이벤트가 부모 컴포넌트에서 적절히 수신되고 있는지 확인해야 합니다.

  3. 부모 컴포넌트에서 데이터 설정: 부모 컴포넌트에서 적절하게 v-model.titlev-model.content가 전달되고 있는지 확인합니다. 간단히 올바르게 동작하는지 콘솔 로그를 추가하여 값이 제대로 변경되는지 확인하는 것도 좋습니다.

가능한 해결 방법

  1. v-model의 올바른 사용: PostForm 컴포넌트에서 v-model:titlev-model:content를 제대로 연결했는지 확인합니다. 아래와 같이 단순히 v-model을 사용하여 양방향 바인딩 할 수 있습니다:

    <PostForm v-model:title="form.title" v-model:content="form.content"></PostForm>
    
  2. 이벤트 수신 확인: 부모 컴포넌트에서 update:title, update:content 이벤트가 적절히 수신되고 있는지 확인합니다. 이 이벤트가 수신되지 않으면 데이터가 업데이트되지 않습니다.

  3. 콘솔 로그 추가: 데이터가 변경될 때마다 콘솔에 그 값을 출력해 보세요. 그러면 데이터 바인딩 과정을 추적하는 데 도움이 됩니다.

참고 자료

유사한 문제를 겪은 경우 해결된 다른 사례를 참고하여 효과적으로 문제를 해결할 수 있습니다:

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

bebe님의 프로필 이미지
bebe

작성한 질문수

질문하기