You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>
问题分析与解决方案

核心问题

  1. 对象引用未更新:如果faeko.trickScore()每次返回的是同一个对象引用(仅修改内部属性而非生成新对象),Svelte的响应式系统会认为scores没有变化,因此不会触发子组件重渲染。
  2. 循环逻辑错误:当前forEach循环中每次都会用faeko.trickScore()的结果覆盖newScores,最终只会保留最后一个有效回合的分数,而非累加所有已完成回合的分数。
  3. 冗余代码:响应式块中的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 11:01:33