0

Here's the link to repro (Svelte Playground).

The problem is that when you add a "waypoint" and toggle the checkbox to enable its bearings (thus changing the respective nested object's enabled property), Svelte won't see these changes. I can see that because the effect on the lines 41-44 won't log anything. If I use $inpsect instead, there's also nothing.

let { directions, configuration } = {directions: {waypointsBearings: [], configuration: {bearings: true}}, on: () => {}, configuration: {}}

  // @ts-expect-error It's safe to read the plugin's protected properties here.
  if (!directions.configuration.bearings) {
    console.warn("The Bearings Control is used, but the `bearings` configuration option is not enabled!");
  }

    function addWaypoint() {
        directions.waypointsBearings.push({enabled: false})
        onWaypointsChanged()
    }

  let waypointsBearings: {
    enabled: boolean;
    angle: number;
    degrees: number;
  }[] = $state([]);

  // directions.on("addwaypoint", onWaypointsChanged);
  // directions.on("removewaypoint", onWaypointsChanged);
  // directions.on("movewaypoint", onWaypointsChanged);
  // directions.on("setwaypoints", onWaypointsChanged);

  function onWaypointsChanged() {
    waypointsBearings = directions.waypointsBearings.map((waypointBearing, index) => {
      if (waypointsBearings[index]) return waypointsBearings[index];

      return {
        enabled: configuration.defaultEnabled || !!waypointBearing,
        angle: waypointBearing ? waypointBearing[0] : configuration.angleDefault,
        degrees: waypointBearing
          ? waypointBearing[1]
          : configuration.fixedDegrees
            ? configuration.fixedDegrees
            : configuration.degreesDefault,
      };
    });
  }

  $effect(() => {
    console.log("PIA");
    console.log(waypointsBearings);
  });

  onWaypointsChanged();

(The addWaypoint function is artifical and serves to replace the commented-out directions.on calls. It's here just to replace the real map and its interactivity).

<button onclick={addWaypoint}>Add</button>
<div class="bearings-control {configuration.class}" style="display: {waypointsBearings.length ? 'block' : 'none'}">
  <div class="bearings-control__list">
    {#each waypointsBearings as waypointBearing, i}
      <div
        class="
        bearings-control__list-item
        {waypointBearing.enabled ? 'bearings-control__list-item--enabled' : 'bearings-control__list-item--disabled'}
        "
      >
        <span class="bearings-control__number">{i + 1}. </span>
        <input type="checkbox" bind:checked={waypointBearing.enabled} class="bearings-control__checkbox" />

I assume that this absence of reactivity for the inner objects is just a part of the broader issue (see the context below), but should be enough to start.

Here's some broader context for the problem. I have a working code (Svelte 4) which I'm trying to rewrite to Svelte 5. You can see the working Svelte 4 code here and you can see it in action (see that it actually works fine) here (try clicking the map to add waypoints, so that the "bearings" bar appears).

3
  • If you use $inspect(waypointsBearings) as is intended, you can see enabled, angle & degrees change on interaction, what else did you expect?
    – brunnerh
    Commented Jan 13 at 6:20
  • @brunnerh no, I don't! That's the issue. When I toggle the checkbox for an added waypoint, I don't see any changes. Commented Jan 13 at 8:56
  • No, wait. Actually, I do see the changes when I use $inspect. But if I try to use $effect to react to those changes, then I don't see it triggering. The $effect on the line 41. Inspect by itself is not very useful, when it comes to something except debugging... Commented Jan 13 at 8:58

1 Answer 1

0

The changes apply as expected.

See the warning you get when logging state:

[svelte] console_log_state Your console.log contained $state proxies. Consider using $inspect(...) or $state.snapshot(...) instead
https://svelte.dev/e/console_log_state

Changes to $state do not affect the initial object, they are recorded on top of it via a Proxy. If you want to get the current value of the state, take a $state.snapshot(). If you only want to observe the values during debugging, use $inspect.

3
  • The question is not about inspecting values. The question is that changes to the object do not trigger reactivity. As a side effect, I don't see console.log showing the changes inside the $effect. Fixing it with $inspect is about fixing the consequences of the issue, and not its root. The idea to use $effect (originally) comes from a necessity to react to changing values and update a 3rd-party code accordingly. And this doesn't happen. Commented Jan 13 at 19:06
  • Everything triggers as expected if the values are read. $state.snapshot() will read all properties recursively guaranteeing a reaction. You can also just JSON.stringify the state in the template somewhere and see that everything updates. If any of that is not the case, your example is not representative of your actual problem.
    – brunnerh
    Commented Jan 13 at 19:10
  • OK, yes, with JSON.stringify I can see the changes logged. Thus, the $effect is working (though it was really not obvious). Then the bigger issue must be related to something else. Thanks for pointing that all out. Commented Jan 13 at 19:28

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.