본문 바로가기
Programming/Javascript

Vue todolist 만들기 - 4. Store 적용하기...Post추가/삭제

by Wilkyway 2023. 5. 4.
반응형

Store를 적용해보겠습니다. 

npm i vuex axios  // axios는 나중에 backend 통신을 위해 미리 설치

 
1. store/store.js
기본 post 리스트를 생성하고, 포스트 추가/삭제기능을 구현해놓는다. 기능은 추후 Backend와의 연동을 위해 actions에 구현해놓습니다.

import { createStore } from 'vuex';
// import axios from 'axios';


export const store = createStore({
// export default createStore({
  state:{
    posts: [
      {_id: '1', title: 'apple', body: 'Im apple', creator: 'apple'},
      {_id: '2', title: 'banana', body: 'Im banana', creator: 'banana'},
      {_id: '3', title: 'orange', body: 'Im orange', creator: 'orange'}
    ]
  },
  mutations:{
    updateState(state, payload) {
      Object.keys(payload).forEach((key) => {
        state[key] = payload[key];        
      });
    },
    DELETEPOST(state, post_id){            
      const delete_index = state.posts.findIndex(p=> p._id === post_id);      // 삭제할 포스트의 index 찾기
      state.posts.splice(delete_index,1);      
    },
  },
  actions:{     
    addPost(context, newPost){      
      const id= context.state.posts.length+1;      
      const post={
        _id: id,
        title: newPost.title,
        body: newPost.body,
        creator: newPost.title
      }
      context.commit("updateState", {
        posts: [...context.state.posts, post],
      })   
      // console.log(context.state.user)        
    },
    deletePost(context, post_id){
      context.commit("DELETEPOST", post_id);
    }       
  }
});

 
2. main.js 수정

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { store } from './store/store.js'  // 추가

createApp(App)
.use(router)
.use(store)		// 추가
.mount('#app')

 
3. components/ListofPost.vue수정

<template>
  <ul>
    <li v-for="post in posts.slice().reverse()" :key=post>
      <EachofPost 
        :id=post._id
        :titleOfPost=post.title 
        :bodyOfPost=post.body 
        :creator=post.creator />
    </li>
  </ul>
</template>
<script>
import EachofPost from './EachofPost.vue'

export default {
  name: 'ListofPost',
  components: {
    EachofPost,
  },
  
// 아래 추가 부분
  computed:{
    posts(){
      return this.$store.state.posts;
    }
  }
// 여기까지 추가, 아래는 주석 or 삭제

//   data(){
//     return {
//       posts: [
//         {
//           _id:1,
//           title: 'myPost',
//           body: 'My Post 1',
//           creator: 'apple'
//         },
//         {
//           _id:2,
//           title: 'myPost2',
//           body: 'My Post 2',
//           creator: 'banana'
//         }
//       ]
//     }
//   }
// }
  
}
</script>

<style>
ul{
  padding-left:0;
}
li{
  list-style: none;
}
</style>

 
4. components/AddPost.vue
포스트를 추가하는 기능을 구현합니다. 편의상 작성자는 title과 동일하게 가져가겠습니다.

<template>  
  <div class="new_post">
    <div class="new_post_header">
      <input type="text" name="title" v-model="title" class="title"/>
      <input type="submit" value="Add" @click="addPost" class="submit">
    </div>
    <div class="new_post_body">
      <textarea class="contents" name="body" v-model="body" />
    </div>  
  </div>  
</template>

<script>
export default {  
  data(){
    return {
      title:'제목',
      body:'내용',
    };
  },
  methods:{
    addPost(){
      this.$store.dispatch('addPost',{
        title: this.title,
        body: this.body,
        creator: this.title,
      })
    }
  }
}
</script>

<style>

.new_post{
background-color:#E0EDFB;
/* margin: 5px auto; */
border: 1px solid grey;
border-radius: 10px;  
box-sizing: content-box;
width:100%;
}
.new_post .new_post_header{    
display: flex;
padding: 5px;
}
.new_post .new_post_header .title{
display:inline-block;
text-align: left;
font-size: 24px;  
height: 50px;
width:100%;
color: black;
border: 0px solid black;
background-color:transparent;
}
.new_post .new_post_header .submit{
position: relative;  
font-size:20px;  
color:dimgrey;
background-color: transparent;
border-color: transparent;
}

.new_post .new_post_body{
position: relative;  
font-size: 16px;
color:cadetblue;
text-align: left;

/* padding: 5px; */
}

.new_post .new_post_body .contents{  
position: relative;    
border: 0px;    
left:0;
right:0;
margin: 5px;
width:99%;  
box-sizing: border-box;
background-color:transparent;
}
</style>

 
5. components/EachofPost.vue
포스트를 삭제하는 기능을 구현합니다.

<template>  
  <div class="post">
    <div class="post_header">
      <div class="title">
        {{ id }}
        {{ titleOfPost }}                      
      </div>  
      <button class="close" @click="removeItem">x</button>  
    </div>    
    <div class="post_body">
      {{ bodyOfPost }}
      <div class="creator">
        by {{  creator }}        
      </div>
    </div>  
    
  </div> 
</template>

<script>
export default {
  props:['id','titleOfPost', 'bodyOfPost','creator'],   
  // 아래 추가
  methods:{
    removeItem(){
      this.$store.dispatch("deletePost", this.id)
    }
  }
  // 여기까지 추가부분
}

</script>

<style>

.post{
  /* background-color:blanchedalmond; */
  margin: 5px auto;
  border: 1px solid grey;
  border-radius: 10px;  
  width:100%;
  min-height:100px;
}
.post .post_header{  
  display: flex;
  padding: 5px;
}
.post .post_header .title{
  display:inline-block;
  text-align: left;
  font-size: 24px;  
  height: 50px;
  width:100%;
  color: black;
  border: 0px solid;
  /* background-color:blueviolet; */
}
.post .post_header .close{
  position: relative;  
  font-size:20px;  
  width:20px;
  height:20px;  
  color:dimgrey;
  background-color: transparent;
  border-color: transparent;
}
.post .post_header .edit{
  position: relative;  
  box-sizing: border-box;
  font-size:20px;  
  width:20px;
  height:20px;  
  color:dimgrey;
  background-color: transparent;
  border-color: transparent;
}

.post .post_body{
  font-size: 16px;
  color:cadetblue;
  text-align: left;
  padding: 5px;
  border: 0px solid;
  /* background-color: orange; */
  width: 100%;
  min-height: 25px;
}
.post .post_body .creator{
  text-align: right;
  left:0;
  right: 0;
  top: 0;
  bottom: 0;
  margin-right: 10px;
  margin-bottom: 5px;
  /* right: 10px; */
}
.post .post_body textarea{
  width: 95%;
  min-height:24px;
  border: 0px;
  font-size: 16px;
  color:cadetblue;
}
</style>
반응형

댓글