Vue cli 3道具(父到子)子在父变量更改后永远不会更新
Posted
技术标签:
【中文标题】Vue cli 3道具(父到子)子在父变量更改后永远不会更新【英文标题】:Vue cli 3 props (parent to child) child never update after the variable in parent has changed 【发布时间】:2020-12-13 00:45:06 【问题描述】:我尝试使用 Vue CLI 3 制作一个聊天应用程序,并且我已经完成了一个实时聊天室的制作。然后,我尝试给它一个引用功能,用户可以引用之前的消息并回复它。因此,我设法通过道具将引用的消息传递给子组件。默认情况下,引用的消息为 NULL
。用户点击一些按钮后,我预计“被引用消息”的值会发生变化,新值会通过 props 传递给孩子(自动更新)。但实际上并没有。
当我浏览互联网时,我确实发现了几个关于在 props 值更改时更新子组件的问题。所以,我尝试了watch:
、created()
、update()
,但都没有奏效。
我曾经尝试在子组件中直接添加一个元素<p>
,然后将cited_message
放入其中,看看变量里面是什么。然后,Vue 应用程序崩溃并留下一个白色的空白页面(但控制台没有显示任何错误)。
为了方便,我认为问题出在:
<CreateMessage:name="name":cited_message="this.cited_message"@interface="handleFcAfterDateBack"/>
或
props: ["name","cited_message"],
watch: cited_message: function (newValue) this.c_message = newValue; ,
您可以ctrl+F
搜索以上代码以节省您的时间。
父组件:
<template>
<div class="container chat">
<h2 class="text-primary text-center">Real-time chat</h2>
<h5 class="text-secondary text-center"> name </h5>
<div class="card" style="min-height: 0.8vh">
<div class="card-body">
<p class="text-secondary nomessages" v-if="messages.length == 0">
[no messages yet!]
</p>
<div class="messages" v-chat-scroll=" always: false, smooth: false ">
<div v-for="message in messages" :key="message.id">
<div v-if="equal_name(message)">
<div class="d-flex flex-row">
<div class="text-info">
[ message.name ] : message.message
</div>
<div class="btn-group dropright">
<a
class="btn btn-secondary btn-sm dropdown-toggle"
href="#"
role="button"
id="dropdownMenuLink"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<button
@click="get_cited_message(message)"
:key="message.id"
class="dropdown-item"
href="#"
>
Cite
</button>
</div>
</div>
<div class="text-secondary time">
<sub> message.timestamp </sub>
</div>
</div>
<!--below is for cited message-->
<div v-if="message.cited_message" class="d-flex flex-row">
Cited : message.cited_message
</div>
</div>
<div v-else>
<div class="d-flex flex-row-reverse">
<div class="text-info">
[ message.name ] : message.message
</div>
<div class="text-secondary time">
<sub> message.timestamp </sub>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-action">
<CreateMessage
:name="name"
:cited_message="this.cited_message"
@interface="handleFcAfterDateBack"
/>
</div>
</div>
</div>
</template>
<script>
import CreateMessage from "@/components/CreateMessage";
import fb from "@/firebase/init.js";
import moment from "moment";
export default
name: "Chat",
props:
name: String,
,
components:
CreateMessage,
,
methods:
equal_name(message)
if (message.name == this.name)
return true;
else
return false;
,
get_cited_message(message)
this.cited_message = message.message;
console.log(this.cited_message);
,
handleFcAfterDateBack(event)
console.log("data after child handle: ", event);
,
,
data()
return
messages: [],
cited_message: null,
;
,
created()
let ref = fb.collection("messages").orderBy("timestamp");
ref.onSnapshot((snapshot) =>
snapshot.docChanges().forEach((change) =>
change.type = "added";
if (change.type == "added")
let doc = change.doc;
this.messages.push(
id: doc.id,
name: doc.data().name,
message: doc.data().message,
timestamp: moment(doc.data().timestamp).format(
"MMMM Do YYYY, h:mm:ss a"
),
cited_message: doc.data().cited_message,
);
);
);
,
;
</script>
<style>
.chat h2
font-size: 2.6em;
margin-bottom: 0px;
.chat h5
margin-top: 0px;
margin-bottom: 40px;
.chat span
font-size: 1.2em;
.chat .time
display: block;
font-size: 0.7em;
.messages
max-height: 300px;
overflow: auto;
text-align: unset;
.d-flex div
margin-left: 10px;
</style>
子组件:
<template>
<div class="container" style="margin-bottom: 30px">
<form @submit.prevent="createMessage()">
<div class="form-group">
<input
type="text"
name="message"
class="form-control"
placeholder="Enter your message"
v-model="newMessage"
/>
<p v-if="c_message" class="bg-secondary text-light">Cited: c_message</p>
<p class="text-danger" v-if="errorText"> errorText </p>
</div>
<button class="btn btn-primary" type="submit" name="action">
Submit
</button>
</form>
</div>
</template>
<script>
import fb from "@/firebase/init.js";
import moment from "moment";
export default
name: "CreateMessage",
props: ["name","cited_message"],
watch:
cited_message: function (newValue)
this.c_message = newValue;
,
data()
return
newMessage: "",
errorText: null,
c_message: null
;
,
methods:
createMessage()
if (this.newMessage)
fb.collection("messages")
.add(
message: this.newMessage,
name: this.name,
timestamp: moment().format(),
cited_message: this.c_message
)
.then(function(docRef)
console.log("Document written with ID: ", docRef.id);
)
.catch((err) =>
console.log(err);
);
this.newMessage = null;
this.errorText = null;
else
this.errorText = "Please enter a message!";
,
,
beforeMount()
this.c_message = this.cited_message;
;
</script>
旁注:在父组件中,我只为左侧的消息制作了下拉菜单。如果这个线程解决了,我会完成右手边。
【问题讨论】:
【参考方案1】:解决了。我认为问题在于父组件中的变量更新时子组件没有重新渲染。只有父组件被重新渲染。因此,子项中的道具值仍然是初始值。为了解决这个问题,使用 v-bind:key 绑定元素可以让 Vue 应用程序跟踪变量的变化(就像某种提醒应用程序跟踪对键所做的更改的提醒)。当变量(键)发生变化时,应用程序会被注意到并将新值传递给孩子。
例如 原创
<CreateMessage
:name="name"
:cited_message="this.cited_message"
@interface="handleFcAfterDateBack"
/>
解决了
<CreateMessage
:name="name"
:cited_message="this.cited_message"
@interface="handleFcAfterDateBack"
:key="this.cited_message"
/>
即使问题解决了,我也不知道我是否清楚地理解了这个问题。如果我犯了任何错误,请发表评论并告诉我。
【讨论】:
以上是关于Vue cli 3道具(父到子)子在父变量更改后永远不会更新的主要内容,如果未能解决你的问题,请参考以下文章