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

Glimmer.js中filtered属性触发UntrackedPropertyError求助

Fixing UntrackedPropertyError for filtered Property in Glimmer.js

Hey there! Let's break down why you're seeing that UntrackedPropertyError and how to fix it.

The Root Cause

Glimmer.js's reactive system relies on the @tracked decorator to know when properties change so it can update the template. In your code, the filtered property is part of plain JavaScript objects in your dogHouse array—these nested properties aren't tracked by default. When your template accesses {{dog.filtered}}, Glimmer detects that this property isn't being tracked and throws the error to prevent stale UI state.

Step-by-Step Solution

1. Create a Tracked Dog Class

First, define a class for your dog objects where all properties (including filtered) are decorated with @tracked. This tells Glimmer to monitor changes to these properties:

import { tracked } from '@glimmer/tracking';
import Component from '@glimmer/component';

class Dog {
  @tracked breed;
  @tracked image;
  @tracked filtered;

  constructor(breed, imageUrl) {
    this.breed = breed;
    this.image = imageUrl;
    this.filtered = false; // Default to showing all dogs initially
  }
}

export default class DoggyAppGlimmer extends Component {
  @tracked dogHouse = [];
  @tracked filterValue = '';

  // Rest of your component code goes here...
}

2. Use the Tracked Class When Fetching Data

Update your didInsertElement hook to create Dog instances instead of plain objects. This ensures every dog's properties are tracked, plus we'll use Promise.all to handle all fetch requests more efficiently:

didInsertElement() {
  fetch('https://dog.ceo/api/breeds/list/all')
    .then(response => response.json())
    .then(data => {
      const breedPromises = Object.keys(data.message).map(breed => {
        return fetch(`https://dog.ceo/api/breed/${breed}/images/random`)
          .then(response => response.json())
          .then(image => new Dog(breed, image.message));
      });

      Promise.all(breedPromises).then(dogs => {
        this.dogHouse = dogs;
      });
    });
}

3. Simplify the Filter Handler

Now that filtered is a tracked property, you don't need to reassign the entire dogHouse array to trigger updates. Just update each dog's filtered property directly:

filterHandler(e) {
  this.filterValue = e.target.value.trim().toLowerCase();
  const filter = this.filterValue;

  this.dogHouse.forEach(dog => {
    // Make filtering case-insensitive for better user experience
    dog.filtered = dog.breed.toLowerCase().includes(filter);
  });
}

4. Tweak the Template for Reliability

Your existing template works, but swapping onkeyup for the input event makes it trigger for all value changes (like pasting text), which is more reliable:

<div>
  dog house
  <input 
    value={{filterValue}} 
    placeholder="Find a doggo" 
    {{on "input" this.filterHandler}} 
  />
  {{#each this.dogHouse key="@index" as |dog|}}
    {{#if dog.filtered }}
      <div>
        <h1>{{dog.breed}}</h1>
        <img src={{dog.image}} alt={{dog.breed}} />
      </div>
    {{/if}}
  {{/each}}
</div>

Why This Works

By wrapping your dog data in a tracked class, you're telling Glimmer exactly which properties to monitor. When you update dog.filtered, Glimmer detects the change and automatically re-renders the relevant parts of the template—no need to recreate the entire array.

内容的提问来源于stack exchange,提问作者Joseph Morales

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:04:36