이전에 올린 1, 2, 3을 보면 Vue3에 추가된 Composition API를 제대로 안쓰고 기존 방식으로 진행했었는데,
그제어제오늘 Compositon API를 쓸 때랑 안쓸때랑 비교해보니 쓰는게 확실히 편함.
그래서 미완코드를 Composition API로 바꿀거쉽니다. Composition API 관련된건 새글 파서 여기에 곧 링크를 걸을 예정.
대충 어떻게 바뀌는지만 보이자면
App.vue 기존 코드
<script>
import AddCard from "./components/AddCard.vue";
import ButtonElement from "./components/ButtonElement.vue";
import TodoMain from "./components/TodoMain.vue";
export default {
name: "App",
components: { TodoMain, AddCard, ButtonElement },
data() {
return { addCard: false };
},
methods: {
showCard() {
this.addCard = true;
},
},
};
</script>
App.vue Composition API script setup 사용한 코드
<script>
import AddCard from "./components/AddCard.vue";
import ButtonElement from "./components/ButtonElement.vue";
import TodoMain from "./components/TodoMain.vue";
export default {
name: "App",
components: { TodoMain, AddCard, ButtonElement },
};
</script>
<script setup>
import { ref } from "vue";
const addCard = ref(false);
const showCard = () => {
addCard.value = true;
};
</script>
그릏다. script setup에서는 선언한 녀석들을 그냥 template에 때려박을 수 있다!!! 근데 반응형인 값은 ref나 reactive 를 써야하는데 reactive 는 좀 킹받는 부분이 있어서 ref 쓰는게 편혀. 그리고 name 이나 component 부분은 그냥 script에 써줘야..함. component 부분은 헷갈리는데 name의 경우 아직 script setup 에서 쓸 방법이 없다는듯.
암튼 저렇게 다 바꿔준다.
이제 추가하기 버튼 보여주는것 바꿀거임. 방법은 App.vue에서 만든 showCard 함수를 props 로 AddCard 컴포넌트에 내려주고 close에 클릭이벤트로 넣는것! 그리고 addCard.value = true; 를 addCard.value = !addCard.value 로 바꿔주고 addCard가 false 일때 Add card 버튼이 안보이게 할 거쉬다.
//App.vue
<template>
<img alt="Vue logo" src="./assets/logo.png" />
<todo-main></todo-main>
<button-element @click="showCard" v-if="!addCard">Add card</button-element>
<add-card v-if="addCard" :closeCard="showCard"></add-card>
</template>
<script>
import AddCard from "./components/AddCard.vue";
import ButtonElement from "./components/ButtonElement.vue";
import TodoMain from "./components/TodoMain.vue";
export default {
name: "App",
components: { TodoMain, AddCard, ButtonElement },
};
</script>
<script setup>
import { ref } from "vue";
const addCard = ref(false);
const showCard = () => {
addCard.value = !addCard.value;
};
</script>
//AddCard.vue
<template>
<section>
<button-element @click="props.closeCard">close</button-element>
<input-element title="title"></input-element>
<input-element title="comment"></input-element>
<button-element>save</button-element>
</section>
</template>
<script>
import ButtonElement from "./ButtonElement.vue";
import InputElement from "./InputElement.vue";
export default {
components: { InputElement, ButtonElement },
name: "AddCard",
};
</script>
<script setup>
import { defineProps } from "vue";
const props = defineProps({
closeCard: Function,
});
</script>
script setup에서는 defineProps 를 이용하여 props 를 받을 수 있다. const 변수명 = defineProps({ 명칭: 타입, 명칭: 타입, ... }); 의 형식으로 적어주고 사용할때는 변수명.명칭 으로 쓰면 된다.
그리고 v-if를 사용해서 Add card의 노출여부를 정해주었다.
그리고 스토어에서 뮤테이션 함수를 만들어준다. 딱히 아직 모듈분리 안해도 될 것 같아서 안함.
// store/index.js
import { createStore } from "vuex";
export default createStore({
state: {
todoList: [
{
id: 0,
title: "제목이다!",
comment:
"마라탕에 푸주, 두부피, 죽순, 어묵만 가득 채워서 먹어보고싶다.",
done: false,
},
{
id: 1,
title: "제목이다!제목이다!",
comment: "영어공부를 좀 혀야하는디 에혀 우짜냐",
done: false,
},
{
id: 2,
title: "제목이다!제목이다!제목이다!",
comment: "뷰 생각보다 재밌다 하지만 여전히 리액트가 너무 좋은.",
done: false,
},
],
},
getters: {},
mutations: {
addItem(state, object) {
let item = {
id: state.todoList.length,
...object,
};
state.todoList.push(item);
},
removeItem(state, id) {
state.todoList = state.todoList.filter((x) => id !== x);
},
editItem(state, object) {
state.todoList[object.id - 1] = object;
},
doneItem(state, id) {
state.todoList[id - 1].done = !state.todoList[id - 1].done;
},
},
actions: {},
modules: {},
});
mutations 부분을 보면 됨. 솔직히 뇌에 힘 안주고 쭉쭉적어서 제대로 돌아갈 진 모르겠다. 이제 각 버튼에 넣어주고 확인해봐야함.
각각 닉값하게 만들었다. vuex의 편한점이 state.어쩌구 = 어쩌구 이런 식으로 쓰면 바로 바꿔주는게.. 너무 좋다. 리덕스 그넘은 액션에서 리듀서로 거쳐야 허는디 으휴 쓸것두많은넘 ㅉㅉ 그래도 좋아해...
*며칠 쉬다가 여기부터 글 다시 적기...
이제 추가하기 기능 넣을거임.
그 전에 나는 input 컴포넌트를 분리했는데 이렇게되면 input컴포넌트에서 상위컴포넌트인 AddCard로 input 데이터를 쏘아주어야함.
//App.vue
<template>
<input-element v-model="title"></input-element>
</template>
<script>
import { ref } from "vue";
const title = ref("");
</script>
만약 App.vue 에서 조금이라도 복잡해진 하위 컴포넌트의 input 값을 가져오려고 v-model을 쓸 때, 위의 예시처럼 저렇게만 하면 ref에 값이 저장이 안됨.
상위컴포넌트가 하위컴포넌트의 input 값을 가져오게 해주려면 우선 하위컴포넌트를 아래와 같이 변경해주어야 함.
//InputElement.vue
<template>
<label>
<h3>{{ props.title }}</h3>
<input :value="value" @input="emits('update:value', $event.target.value)" />
</label>
</template>
<script>
export default {
name: "InputElement",
};
</script>
<script setup>
import { defineProps, defineEmits } from "vue";
const props = defineProps({
title: String,
value: String,
});
const emits = defineEmits(["update:value"]);
</script>
하위컴포넌트인 InputElement에서 props와 emit을 지정해주자. props.value 가 input의 value가 될거고 v-model이 이 값을 내려다줄것임. 그리고 emits 를 통해 업데이트 된 값을 올려다줘야함. "update:어쩌구" 로 만들어주고 @input="emits('update:어쩌구',$event.target.value)" 하면 됨.
그리고 상위 컴포넌트의 v-model 을 v-model:value 이렇게 바꿔주면 끝.
//App.vue
<template>
<input-element v-model:value="title"></input-element>
</template>
<script>
import { ref } from "vue";
const title = ref("");
</script>
위의 코드들에서 중요한 부분은
<input :value="value" @input="emits('update:value', $event.target.value)" />
const props = defineProps({
value: String,
});
const emits = defineEmits(["update:value"]);
<input-element v-model:value="title"></input-element>
이 세개임. 여기서 원하는대로 색칠된 부분 명칭 바꿔서 써주면 된다. title 부분은 바꾸려면 ref 명칭도 바꿔줘야함.
아무튼 위의 방식을 이용해서 input의 값을 잘 가져온다면 저장기능을 이렇게 만들어준다.
//AddCard.vue
<template>
<section>
<button-element @click="props.closeCard">close</button-element>
<input-element
type="text"
title="title"
v-model:value="title"
></input-element>
<input-element
type="text"
title="comment"
v-model:value="comment"
></input-element>
<button-element @click="saveItem">save</button-element>
</section>
</template>
<script>
import ButtonElement from "./ButtonElement.vue";
import InputElement from "./InputElement.vue";
export default {
components: { InputElement, ButtonElement },
name: "AddCard",
};
</script>
<script setup>
import { defineProps, ref } from "vue";
import { useStore } from "vuex";
const props = defineProps({
closeCard: Function,
});
const store = useStore();
const title = ref("");
const comment = ref("");
const saveItem = () => {
if (!title.value) {
alert("제목을 적어주세요");
return;
} else {
store.commit("addItem", {
title: title.value,
comment: comment.value,
done: false,
});
title.value = "";
comment.value = "";
}
};
</script>
<template> 안의 <button-element @click="saveItem">save</button-element> 는 save 버튼을 누르면 saveItem 을 실행시켜준다.
saveItem 은 title, comment 각각의 ref에 저장된 값을 가져오고 commit 을 이용하여 스토어의 mutations 함수 중 addItem을 사용한다. addItem은 스토어에 넘어온 객체를 저장해준다. 그 후 title, comment 를 공란으로 비워주면 끝. 예외처리로는 제목이 비었을 경우만 해놓았음. 투두리스트니까 제목만 간결하게 적어서 쓸 수 있으니까!
잘 된당...
이거 하나 됐으면 다른 기능 추가하는건 어렵지 않을 테니까....잘거임 20000
'프로젝트' 카테고리의 다른 글
Vue 3 + Vuex 로 Todo-List 만들어보기 (3) (0) | 2022.04.29 |
---|---|
Vue 3 + Vuex 로 Todo-List 만들어보기 (2) (0) | 2022.04.27 |
Vue 3 + Vuex 로 Todo-List 만들어보기 (1) (0) | 2022.04.25 |