Svelte中ScoreBoard组件未随game.tricks更新重渲染问题
问题描述
我创建了一个ScoreBoard组件,用于在回合(trick)完成时渲染分数。当game.tricks更新时,getRunningScores()会被调用且控制台显示scores已更新,但<ScoreBoard />组件却未触发重渲染。
调试代码:
$: console.log("当前回合的得分 ", scores);
相关代码
export let game = { deck: undefined, players: [], tricks: [], contract: {}, }; let scores = null; // scores = {'0_1': 0, '2_3': 0} (对象结构)
$: { game.tricks; scores = getRunningScores(); scores = scores }
function getRunningScores() { console.log("called"); let newScores = {}; if (game?.tricks?.length > 0) { // 当前回合是否完成? let skipLast = !faeko.isTrickComplete(); game.tricks.forEach((_, i) => { // 如果回合未完成则跳过最后一个 if (skipLast) { if (i >= game.tricks.length - 1) return; } newScores = faeko.trickScore(); newScores = newScores; console.log("各队伍得分 ", newScores); }); } return newScores; }
<div class:score-board={game?.tricks?.length > 0}> {#if game.tricks && game.tricks.length > 0} <ScoreBoard players={game?.players} scores={scores} /> {:else} <div class="contract-div"> <p class="label">Score</p> <div class="contract-container"> <span class="nick-name"></span> <div class="contract"> <div class="value"> <span></span> </div> </div> <div class="dblRdbl"></div> </div> </div> {/if} </div>
问题分析与解决方案
核心问题
- 对象引用未更新:如果
faeko.trickScore()每次返回的是同一个对象引用(仅修改内部属性而非生成新对象),Svelte的响应式系统会认为scores没有变化,因此不会触发子组件重渲染。 - 循环逻辑错误:当前
forEach循环中每次都会用faeko.trickScore()的结果覆盖newScores,最终只会保留最后一个有效回合的分数,而非累加所有已完成回合的分数。 - 冗余代码:响应式块中的
scores = scores完全多余,不会触发任何更新。
修复步骤
1. 确保返回新的对象引用并修正累加逻辑
修改getRunningScores,初始化基础分数对象并累加每回合得分,同时每次生成新对象确保引用更新:
function getRunningScores() { console.log("called"); // 初始化分数对象,匹配预期结构 let newScores = { '0_1': 0, '2_3': 0 }; if (game?.tricks?.length > 0) { let skipLast = !faeko.isTrickComplete(); game.tricks.forEach((_, i) => { // 跳过未完成的最后一个回合 if (skipLast && i >= game.tricks.length - 1) return; // 获取当前回合得分并累加 const trickScore = faeko.trickScore(); // 生成新对象,确保引用变化 newScores = { '0_1': newScores['0_1'] + trickScore['0_1'], '2_3': newScores['2_3'] + trickScore['2_3'] }; console.log("各队伍得分 ", newScores); }); } return newScores; }
2. 简化响应式声明
将响应式块简化为直接依赖game.tricks,去掉冗余代码:
$: scores = getRunningScores();
3. 确保子组件响应props变化
如果ScoreBoard是自定义组件,需确保内部能正确监听scores的变化。可以在组件内添加响应式声明:
<script> export let scores; // 监听scores变化触发内部更新 $: currentScores = scores; </script>
额外说明
Svelte的响应式更新依赖值的引用变化(对象/数组)或值本身的变化(基本类型)。传递对象给子组件时,必须确保每次更新都生成新的对象引用,才能触发子组件重渲染。
内容的提问来源于stack exchange,提问作者balaji
相关产品推荐
相关产品推荐

