IT이야기

Vuex + vue-roouter에서 중앙 집중화된 상태로 분리된 구성 요소

cyworld 2022. 4. 1. 22:25
반응형

Vuex + vue-roouter에서 중앙 집중화된 상태로 분리된 구성 요소

공유 상태의 문제는 서로 다른 구성 요소에서 작용과 돌연변이를 재사용하기 어렵다는 것이다.

우리가 구성 요소를 가지고 있다고 상상해 봅시다.Votes이 구성요소는 사용자가 항목에 대해 투표할 수 있도록 허용한다.

const Votes = {
  template: `<span>
        <i>{{ item.votes }}</i> <a href="#" @click.prevent="upvote">+</a>
    </span>
    `,
   methods: {
     upvote: function() {
       this.$store.dispatch('upvote', this.item.id)
     }
   },
   props: ['item']
}

따라서 사용자가 클릭할 때+, 액션upvote파견이다.

그러나 이 구성요소를 두 개의 보기에서 재사용하는 방법, 모든 항목을 나열하는 목록 및 항목에 대한 세부 정보를 표시하는 세부 정보.

두 경우 모두 사용자가 항목에 대해 투표할 수 있도록 허용한다.

상세보기 목록 보기

부에루터

사용자는 URL을 통해 탐색할 수 있다(예:/item/a

이 경우 에서는 라우터 매개 변수를 사용하여 데이터베이스에서 항목을 찾아야 한다.

가게.아이템이 비어있어!


문제는 가게에서 시작된다.

state: { items: [], opened: {} },
  actions: {
    open: function({commit, state}, payload) {
        let it = db.find(item => payload === item.id) // Find in db because user can navigate via Copy/Paste URL
      commit('SET_OPENED', it)
    },
    upvote: function({commit, state}, payload) {
        let it = state.items.find(item => payload === item.id) // Problem here, state.items is when i vote in ListingView, in ItemView (our details view) should use state.opened
      commit('SET_VOTE', { id: it.id, votes: it.votes + 1 })
    }
  },
  mutations: {
    SET_VOTE: function(state, payload) {
            let it = state.items.find(item => payload.id === item.id) // Problem here, state.items is when i vote in ListingView, in ItemView (our details view) should use state.opened
      console.log('Voted', db, it)
      Vue.set(it, 'votes', payload.votes)
    },
    SET_OPENED: function(state, payload) {
        Vue.set(state, 'opened', payload)
    }
  }

upvote그리고SET_VOTE다양한 점(diffents points, differents view)에서 호출되는 동작과 돌연변이여서 상태는 different이다.

질문

다른 상태와 다른 관점에서 동일한 작업/연구를 재사용하는 방법

[추가] 기억하십시오.

  1. 사용자가 URL을 통해 탐색할 수 있음(예:/item/a그리고 아이템을 표시해야 한다.
  2. Objetive는 재사용 작업/교체 및 구성품이다.따라서 모두 복제해도 이 문제는 해결되지 않는다.

전체 소스...

const db = [{
  id: 'a',
  name: 'Item #1',
  image: 'http://lorempicsum.com/simpsons/350/200/1',
  votes: 0
}, {
  id: 'b',
  name: 'Item #2',
  image: 'http://lorempicsum.com/simpsons/350/200/2',
  votes: 0
}, {
  id: 'c',
  name: 'Item #3',
  image: 'http://lorempicsum.com/simpsons/350/200/3',
  votes: 0
}]

const Votes = {
  name: 'Votes',
  template: `<span>
	  	<i>{{ item.votes }}</i> <a href="#" @click.prevent="upvote">+</a>
    </span>
	`,
  methods: {
    upvote: function() {
      this.$store.dispatch('upvote', this.item.id)
    }
  },
  props: ['item']
}

const ListingView = {
  name: 'ListingView',
  template: `
    <ul class="listing">
    	<li v-for="item in $store.state.items">
				<router-link :to="{ name: 'item', params: { id: item.id }}">
      		<img :src="item.image" />
	  	    <br>{{ item.name }}	      
	      </router-link>
      	Votes: <votes :item=item></votes> 
    	</li>
		</ul>
  `,
  created() {
    this.$store.dispatch('fetch')
  },
  components: {
    Votes
  }
}

const ItemView = {
  name: 'ItemView',
  template: `<div class="item-view">
  		<router-link class="back-listing" :to="{name: 'listing'}">Back to listing</router-link>
	  	<div class="item">
  	  	<h1>{{ item.name }} <votes :item=item></votes> </h1>
    		<img :src="item.image" />
	    </div>
		</div>
  </div>`,
  computed: {
    item: function() {
      return this.$store.state.opened
    }
  },
  created() {
    this.$store.dispatch('open', this.$route.params.id) // I need this because user can navigate via Copy/Paste URL
  },
  components: {
    Votes
  }
}

const store = new Vuex.Store({
  state: {
    items: [],
    opened: {}
  },
  actions: {
    fetch: function({
      commit, state
    }, payload) {
      commit('SET_LIST', db.map(a => Object.assign({}, a))) // Just clone the array
    },
    open: function({
      commit, state
    }, payload) {
      let it = db.find(item => payload === item.id) // Find in db because user can navigate via Copy/Paste URL
      commit('SET_OPENED', it)
    },
    upvote: function({
      commit, state
    }, payload) {
      let it = state.items.find(item => payload === item.id) // Problem here, state.items is when i vote in ListingView, in ItemView should use state.opened
      commit('SET_VOTE', {
        id: it.id,
        votes: it.votes + 1
      })
    }
  },
  mutations: {
    SET_VOTE: function(state, payload) {
      let it = state.items.find(item => payload.id === item.id) // Problem here, state.items is when i vote in ListingView, in ItemView should use state.opened
      console.log('Voted', db, it)
      Vue.set(it, 'votes', payload.votes)
    },
    SET_OPENED: function(state, payload) {
      Vue.set(state, 'opened', payload)
    },
    SET_LIST: function(state, payload) {
      Vue.set(state, 'items', payload)
    }
  }
})
const router = new VueRouter({
  routes: [{
    name: 'listing',
    path: '/',
    component: ListingView
  }, {
    name: 'item',
    path: '/item/:id',
    component: ItemView
  }]
})
new Vue({
  el: '#app',
  store,
  router
})
* {
  box-sizing: border-box;
}
.listing {
  list-style-type: none;
  overflow: hidden;
  padding: 0;
}
.listing li {
  float: left;
  width: 175px;
  text-align: center;
  border: 1px #ddd solid;
  background: white;
  margin: 5px;
  cursor: pointer;
}
.listing li img {
  width: 100%;
  margin-bottom: 4px;
}
.listing li > a:hover {
  background: #eee;
}
.item-view {
  text-align: center;
}
.item {
  padding: 10px;
}
a {
  font-size: 16px;
  display: inline-block;
  padding: 10px;
  border: 1px #ddd solid;
  background: white;
  color: black;
  margin: 10px;
  &.back-listing {
    position: absolute;
    left: 0;
    top: 0;
  }
}
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuex/dist/vuex.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
  <router-view></router-view>
</div>

또는 fanddle: http://jsfiddle.net/Ridermansb/sqmofcbo/3/

Vue Forum에서 다른 게시물(크로스 포스트링)

코드를 간략히 살펴보면, 현재 항목을 복사하는 것이 주로 문제임state.opened. 대신 현재 열려 있는 항목의 ID에 대한 참조를 저장하십시오.state.opened그리고 그 아이디를 수정하는데 사용한다.state.items.

수리 작업에 대한 몇 가지 추가 코멘트가 있는 작업 예제.

http://jsfiddle.net/d30o31r8/

참조URL: https://stackoverflow.com/questions/40871074/decoupled-components-with-centralized-states-in-vuex-vue-router

반응형