BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / iwhisper / #6763952同步于 2024/1/21
该镜像源已超过 30 天没有更新,可能在源站已被删除。
IWhisper机器人发帖

【求助】【vue3】来个佬救救孩子

IWhisper#705
2024/1/21镜像同步3 回复
凭我后端的经验vue要重新渲染可以给组件用:key=‘a’,每次a++就行了,不知道有没有用
订阅后,新回复会通过你的通知中心匿名送达。
3 条回复
IWhisper#705机器人#0 · 2024/1/21
<pre class="markdown"># issue **ts对象的属性更新后没能触发组件重新渲染以及watch/watchEffect** 前端通过websocket接收到后端发送的消息后,自动分配给对应的函数处理,控制台打印出来game对象已经更新了,但是没有重新渲染,也没触发watch。主要代码为 ```typescript public websocket: WebSocketService | undefined; // 自动管理websocket消息 this.websocket.on('match',async (data:any) =&gt; await this.match_response_handler(data)); // 绑定处理函数 ``` 其中websocket为一个自动管理websocket协议通信的对象, match_response_handler是对应的响应函数,会修改game对象的属性。 gpt4提到:如果 `match_response_handler` 方法是在 Vue 的作用域之外被调用的(例如,通过一个非 Vue 的回调函数),那么 Vue 可能无法追踪到这些变化。我尝试使用它建议的箭头函数或match_response_handler.bind(this)均未解决问题。 以及,我在Game类的其它方法类通过setTimeOut修改属性(而不是通过webSocketService自动调用的)会正确触发watch、重新渲染。 部分相关源码如下: main.vue ```vue &lt;template&gt; &lt;div v-if="!isLoaded"&gt; // some code &lt;/div&gt; &lt;div v-if="isLoaded"&gt; // some code &lt;el-col v-for="(card, index) in game.getSelfCards()" :key="card.name"&gt; {{ card.name }} &lt;/el-col&gt; &lt;/div&gt; &lt;/template&gt; &lt;script setup lang="ts"&gt; // some import let game = ref(new Game()) let { cards } = toRefs(game.value) let isLoaded = ref(false) watchEffect(()=&gt;{ isLoaded.value = game.value.isLoaded }) watch(cards, (newV, oldV) =&gt; { console.log("update cards", newV) }, { immediate: true, deep: true }) watch(()=&gt;game.value.isLoaded, ()=&gt;{ console.log("update game.value.isLoaded", game.value.isLoaded) }, { immediate: true, deep: true }) onMounted(() =&gt; { // 渲染完成后再初始化,不然不会更新 game.value.finiteStateAutomata() // 迭代 }) &lt;/script&gt; ``` Game.ts ```typescript //some import class Game { public isLoaded: boolean = false; public cards: Card[]; public websocket: WebSocketService | undefined; // 自动管理websocket消息 public async match_response_handler(data: any) { this.selfIndex = data.idx; for (var name in data.decks)this.cards.push(new Card(name)); for (var name in data.cards)this.getSelfCards().push(new Card(name)); this.isLoaded = true; await nextTick() // console.log("Receive response match", data,this); } // note this private initWebsocketService() { // will be called if(!this.websocket)return this.websocket.on('match',async (data:any) =&gt; await this.match_response_handler(data)); } } export { Game }; ``` webSocketService.ts ```typescript // some import class WebSocketService { private socket: WebSocket; private handlers: { [key: string] : (ret: any) =&gt; void }; constructor(url: string) { this.socket = new WebSocket(url); this.handlers = {}; this.socket.onmessage = async (event) =&gt; { const response: ApiResponse =await JSON.parse(event.data); console.log(`收到来自服务器的数据:`, response); await this.handleMessage(response); }; } private async handleMessage(response: ApiResponse) { const handler = this.handlers[response.api]; if (handler) { await handler(response.ret); } } // note this public on(api: string, handler: (ret: any) =&gt; void) { this.handlers[api] = handler; } } export {WebSocketService}; ```</pre>
IWhisper#309机器人#1 · 2024/1/21
凭我后端的经验vue要重新渲染可以给组件用:key=‘a’,每次a++就行了,不知道有没有用
IWhisper#705机器人#2 · 2024/1/21
这个我试过了,我给最外层的div加key绑定了一个每秒递增的变量,但是貌似没刷新,是因为不会刷新子组件吗