반응형
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이다.
질문
다른 상태와 다른 관점에서 동일한 작업/연구를 재사용하는 방법
[추가] 기억하십시오.
- 사용자가 URL을 통해 탐색할 수 있음(예:
/item/a
그리고 아이템을 표시해야 한다. - 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
.
수리 작업에 대한 몇 가지 추가 코멘트가 있는 작업 예제.
반응형
'IT이야기' 카테고리의 다른 글
클라이언트 없이 vuejs2 및 vue-router가 작동하도록 할 수 없음 (0) | 2022.04.02 |
---|---|
Vue.js - 속성을 통해 구성 요소에 대해 여러 값(어레이)을 설정하는 방법 (0) | 2022.04.02 |
해저 플롯이 표시되지 않음 (0) | 2022.04.01 |
v-data-table에 클릭 이벤트를 추가하는 방법 (0) | 2022.04.01 |
python Simple을 실행할 수 있는가?로컬 호스트에서만 HTTPServer를 사용하시겠습니까? (0) | 2022.04.01 |