Vue.JS 및 Rails-UJS/Jquery-UJS 경합 - Vuex 돌연변이가 작동하지 않음
간단한 튜토리얼을 따르고 있는데 어떤 이유에서인지 뷰 돌연변이 2개(addCard 및 addList)가 올바르게 동작하고 있습니다.하지만 제 세 번째 돌연변이(editCard)는 Vue에서 작동하지 않는 것 같습니다.카드를 클릭하면 이름을 편집할 수 있는 경유지가 나타납니다.저장 시 레일에서 올바르게 저장되지만 브라우저에서 바로 업데이트되지는 않습니다.변경 내용을 보려면 페이지를 새로 고쳐야 합니다.처음에는 Vuex 및 Rails-ujs와의 충돌이라고 생각했지만, 3번째 돌연변이가 작동하지 않는 이유는 무엇입니까? 여기 Vue 전문가의 도움에 감사 드립니다.
앱 / 스크립트 / 앱표시하다
<template>
<div id="app" class="row">
<div class="col-12">
<!-- Button trigger modal -->
<button type="button" data-toggle="modal" data-target="#exampleModal">New List</button>
<!-- Bootstrap Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<textarea ref="message" v-model="message" class="form-control mb-1">
</textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button v-on:click="createList" class="btn btn-secondary">Add</button>
</div>
</div>
</div>
</div>
</div><br/><br/>
<hr /><hr />
<div class="col-2">
<div class="list">
<a v-if="!editing" v-on:click="startEditing">
<h1 style="padding: 20px 20px;">
<span style="font-style: italic;">+ Add a List</span>
</h1>
</a>
<textarea v-if="editing" ref="message" v-model="message" class="form-control mb-1">
</textarea>
<button v-if="editing" v-on:click="createList" class="btn btn-secondary">Add</button>
<a v-if="editing" v-on:click="editing=false">cancel</a>
</div>
</div>
<list v-for="(list, index) in lists" :list="list"></list>
</div>
</template>
<script>
import list from 'components/list'
export default {
components: { list },
data: function() {
return {
editing: false,
message: "",
}
},
computed: {
lists: {
get() {
return this.$store.state.lists;
},
set(value) {
this.$store.state.lists = value
},
},
},
methods: {
startEditing: function () {
this.editing = true
this.$nextTick(() => { this.$refs.message.focus() })
},
createList: function() {
var data = new FormData // -> {}
data.append("list[name]", this.message)// -> { "list[name]" => this.message }
Rails.ajax({
url: "/lists",
type: "POST",
data: data,
dataType: "json",
beforeSend: () => true,// 2xx, 3xx (SUCCESS), 4xx, 5xx (ERROR)
success: (data) => {
this.$store.commit('addList', data)
this.message = ""
this.editing = false
$('#exampleModal').modal('hide');
return false;
}
});
}
}
}
</script>
<style scoped>
.list {
background-color: #e2e4e6;
padding: 8px;
border-radius: 3px;
margin-bottom: 8px;
}
.card {
}
p {
font-size: 2em;
text-align: center;
}
</style>
앱/스크립트/팩/어플리케이션.js
import Vue from 'vue/dist/vue.esm'
import Vuex from 'vuex'
// import BootstrapVue from 'bootstrap-vue' || These are for bootstrap vue removing for now
import App from'../app.vue'
import TurbolinksAdapter from 'vue-turbolinks'
// import 'bootstrap/dist/css/bootstrap.css'; || These are for bootstrap vue removing for now
// import 'bootstrap-vue/dist/bootstrap-vue.css'; || These are for bootstrap vue removing for now
// Vue.use(BootstrapVue); || These are for bootstrap vue removing for now
Vue.use(Vuex)
Vue.use(TurbolinksAdapter)
window.store = new Vuex.Store({
state: {
lists: []
},
mutations: {
addList(state, data) {
state.lists.unshift(data)
},
addCard(state, data) {
const index = state.lists.findIndex(item => item.id == data.list_id)
state.lists[index].cards.push(data)
},
editCard(state, data) {
const list_index = state.lists.findIndex((item) => item.id == data.list_id)
const card_index = state.lists[list_index].cards.findIndex((item) => item.id == data.id)
state.lists[list_index].cards.splice(card_index, 1, data)
},
}
})
document.addEventListener("turbolinks:load", function() {
var element = document.querySelector("#boards")
if (element != undefined) {
window.store.state.lists = JSON.parse(element.dataset.lists)
const app = new Vue({
el: element,
store: window.store,
template: "<App />",
components: { App }
})
}
});
앱 / 스크립트 / 컴포넌트 / 카드표시하다
<template>
<div>
<div @click="editing=true" class="card card-body mb-3">
{{card.name}}
</div>
<div v-if='editing' class="modal-backdrop show"></div>
<div v-if='editing' @click="closeModal" class="modal show" style="display: block">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ card.name }}</h5>
</div>
<div class="modal-body">
<input v-model="name" class="form-control"></input>
</div>
<div class="modal-footer">
<button @click="save" type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['card', 'list'],
data: function () {
return {
editing: false,
name: this.card.name,
}
},
methods: {
closeModal: function(event) {
if (event.target.classList.contains("modal")) {
this.editing = false
}
},
save: function() {
var data = new FormData
data.append("card[name]", this.name)
Rails.ajax({
url: `/cards/${this.card.id}`,
type: "PATCH",
data: data,
dataType: "json",
beforeSend: function() { return true },
success: (data) => {
this.$store.commit('editCard', data)
this.editing = false
}
})
},
}
}
</script>
<style scoped>
</style>
앱 / 스크립트 / 컴포넌트 / 목록표시하다
<template>
<div class="col-2">
<div class="list">
<h6>{{ list.name }}</h6>
<card v-for="card in list.cards" :card="card" :list="list"></card>
<div class="card card-body">
<a v-if="!editing" v-on:click="startEditing">Add a Card</a>
<textarea v-if="editing" ref="message" v-model="message" class="form-control mb-1"></textarea>
<button v-if="editing" v-on:click="createCard" class="btn btn-secondary">Add</button>
<a v-if="editing" v-on:click="editing=false">cancel</a>
</div>
</div>
</div>
</template>
<script>
import card from 'components/card'
export default {
components: { card },
props: ["list"],
data: function () {
return {
editing: false,
message: ""
}
},
methods: {
startEditing: function () {
this.editing = true
this.$nextTick(() => { this.$refs.message.focus() })
},
createCard: function() {
var data = new FormData
data.append("card[list_id]", this.list.id)
data.append("card[name]", this.message)
Rails.ajax({
url: "/cards",
type: "POST",
data: data,
dataType: "json",
beforeSend: function() { return true },
success: (data) => {
this.$store.commit('addCard', data)
this.message = ""
this.$nextTick(() => { this.$refs.message.focus() })
}
});
}
}
}
</script>
<style scoped>
.list {
background-color: #e2e4e6;
padding: 8px;
border-radius: 3px;
margin-bottom: 8px;
}
.btn.btn-secondary {
width: 75px;
}
</style>
업데이트: 카드 편집 및 저장 시 콘솔 로그와 터미널 로그를 업데이트했습니다.
터미널 로그:
Started GET "/lists/" for 127.0.0.1 at 2018-04-24 21:51:47 -0500
Processing by ListsController#index as HTML
Rendering lists/index.html.erb within layouts/application
List Load (11.3ms) SELECT "lists".* FROM "lists" ORDER BY "lists"."position" DESC
Card Load (0.1ms) SELECT "cards".* FROM "cards" WHERE "cards"."list_id" = ? ORDER BY "cards"."position" ASC [["list_id", 235]]
Card Load (0.1ms) SELECT "cards".* FROM "cards" WHERE "cards"."list_id" = ? ORDER BY "cards"."position" ASC [["list_id", 234]]
Card Load (0.1ms) SELECT "cards".* FROM "cards" WHERE "cards"."list_id" = ? ORDER BY "cards"."position" ASC [["list_id", 233]]
Card Load (0.1ms) SELECT "cards".* FROM "cards" WHERE "cards"."list_id" = ? ORDER BY "cards"."position" ASC [["list_id", 232]]
Card Load (0.1ms) SELECT "cards".* FROM "cards" WHERE "cards"."list_id" = ? ORDER BY "cards"."position" ASC [["list_id", 231]]
Rendered lists/index.html.erb within layouts/application (17.8ms)
Rendered shared/_head.html.erb (203.0ms)
Rendered shared/_navbar.html.erb (0.6ms)
Rendered shared/_notices.html.erb (0.3ms)
Completed 200 OK in 370ms (Views: 346.5ms | ActiveRecord: 11.9ms)
Started PATCH "/cards/106" for 127.0.0.1 at 2018-04-24 21:51:59 -0500
Processing by CardsController#update as JSON
Parameters: {"card"=>{"name"=>"Card C30006"}, "id"=>"106"}
Card Load (0.2ms) SELECT "cards".* FROM "cards" WHERE "cards"."id" = ? LIMIT ? [["id", 106], ["LIMIT", 1]]
(0.0ms) begin transaction
List Load (0.1ms) SELECT "lists".* FROM "lists" WHERE "lists"."id" = ? LIMIT ? [["id", 231], ["LIMIT", 1]]
SQL (0.2ms) UPDATE "cards" SET "name" = ?, "updated_at" = ? WHERE "cards"."id" = ? [["name", "Card C30006"], ["updated_at", "2018-04-25 02:51:59.753283"], ["id", 106]]
(1.7ms) commit transaction
Rendering cards/show.json.jbuilder
Rendered cards/_card.json.jbuilder (0.6ms)
Rendered cards/show.json.jbuilder (2.5ms)
Completed 200 OK in 28ms (Views: 21.7ms | ActiveRecord: 2.2ms)
브라우저 콘솔:
{id: 106, list_id: 231, name: "Card C30006", position: 3, created_at: "2018-04-24T20:39:06.150Z", …}
created_at:(...)
id:(...)
list_id:(...)
name:(...)
position:(...)
updated_at:(...)
url:(...)
__ob__:Observer
dep:Dep {id: 86, subs: Array(0)}
value:{…}
vmCount:0
__proto__:Object
get created_at:ƒ reactiveGetter()
set created_at:ƒ reactiveSetter(newVal)
get id:ƒ reactiveGetter()
set id:ƒ reactiveSetter(newVal)
get list_id:ƒ reactiveGetter()
set list_id:ƒ reactiveSetter(newVal)
get name:ƒ reactiveGetter()
set name:ƒ reactiveSetter(newVal)
get position:ƒ reactiveGetter()
set position:ƒ reactiveSetter(newVal)
get updated_at:ƒ reactiveGetter()
set updated_at:ƒ reactiveSetter(newVal)
get url:ƒ reactiveGetter()
set url:ƒ reactiveSetter(newVal)
__proto__:Object
업데이트 2: (Vuex 패널 출력에 추가)
Vue에는 자동으로 검출할 수 있는 데이터 갱신에 관한 주의사항이 있습니다.https://vuejs.org/v2/guide/list.html#Caveats
또한 대응성 규칙에는 다음과 같은 정보가 있습니다.https://vuex.vuejs.org/en/mutations.html#mutations-follow-vues-reactivity-rules
경고 페이지는 실제로 당신의 상황을 반영하고 있다고 생각합니다.견적:
JavaScript의 제한으로 인해 Vue는 어레이에 대한 다음과 같은 변경을 감지할 수 없습니다.
인덱스로 항목을 직접 설정하는 경우(예:
vm.items[indexOfItem] = newValue
예를 들어 배열의 길이를 수정하는 경우.vm.items.length = newLength
경고 1을 극복하기 위해 다음 두 가지 모두 다음과 같은 작업을 수행합니다.
vm.items[indexOfItem] = newValue
그러나 반응성 시스템에서 상태 업데이트도 트리거합니다.
// Vue.set Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue)
이를 바탕으로 코드를 다음과 같이 업데이트해 보겠습니다.
editCard(state, data) {
const list_index = state.lists.findIndex((item) => item.id == data.list_id)
const card_index = state.lists[list_index].cards.findIndex((item) => item.id == data.id)
var updata = state.lists[list_index].cards[card_index] = data;
state.lists.splice(list_index, 1, updata);
이제 스플라이스를 목록의 최상위 레벨로 이동하면 업데이트가 트리거됩니다.
참고: 피드백이 있으시면 이 답변을 적절히 업데이트해 드리겠습니다.
데이터 속성에서 카드 이름을 표시하고 Ajax 요청 후 워처를 사용하여 이 데이터를 업데이트해야 합니다.
<template>
<div @click="editing=true" class="card card-body mb-3">
{{cardName}}
</div>
</template>
<script>
export default {
props: ['card', 'list'],
data: function () {
return {
editing: false,
name: this.card.name,
cardName: this.card.name
}
},
watch: {
card(value) {
this.cardName = value.name
}
}
}
</script>
새로 고침 문제가 있는 경우 VM을 사용해 볼 수도 있습니다.$forceUpdate()
Rails.ajax가 실제로 jquery-ujs인 경우 오류는 다음과 같습니다.
success: (data) => {
this.$store.commit('editCard', data)
this.editing = false
}
은 다음 .「 」 」 。event, data, status, xhr
한 번 event
이치노
addCard() 변환이 동작하는 이유는 POST 요구를 발행하고 editCard() 변환에서는 패치 요구를 발행하고 있기 때문이라고 생각합니다.
그 때문에 갱신 상태가 표시되지 않는 경우는, 데이터가 JSON 형식이 아닐 가능성이 있습니다.jQuery 문서에 따르면 데이터는 $.ajax 호출의 data Type에 따라 자동으로 포맷됩니다.
어쨌든 데이터 변수를 기록하십시오.
그 원인은 Rails/Rails-UJS. 5.1.5 버전 문제이며, 그 이후에는 "Rails.ajax"에서 작동하지 않는 것 같습니다.내 경우 5.1.4로 복구됩니다.
언급URL : https://stackoverflow.com/questions/49933491/vue-js-and-rails-ujs-jquery-ujs-conflicting-vuex-mutations-not-working
'programing' 카테고리의 다른 글
Vue-repo "모듈 빌드 실패:오류: ESLint 구성을 찾을 수 없습니다." (0) | 2022.08.18 |
---|---|
정수 기반 전원 함수 pow(int, int)를 구현하는 가장 효율적인 방법 (0) | 2022.08.11 |
포인터가 NULL 포인터인지 확인하려면 어떻게 해야 하나요? (0) | 2022.08.11 |
여러 조건의 if 실행 순서 (0) | 2022.08.11 |
VueJS/VueX : 상태 속성이 어레이일 때 워치가 호출되지 않음 (0) | 2022.08.11 |