how to break an endless loop

The following Observable Framework code works but causes an endless loop. Could somebody please explain how to break it?

// code block 1
const appState = Mutable({
  user: {
    name: 'John Doe',
    loggedIn: false
  }
});
const setState = (updates) => {
    appState.value = { ...appState.value, ...updates };
};
// code block 2
function updateState(loggedIn) {
  setState({ user: { ...appState.user, loggedIn } });
  console.log(`state was updated`);
}
// code block 3
updateState(true);
<!-- markdown template -->
<div>Name: ${appState.user.name}, Logged In: ${appState.user.loggedIn}</div>

Thanks a lot in advance.

appState.user references the reactive value, causing updateState() (and any code that references it) to get invalidated whenever the Mutable’s value is reassigned. If you want to avoid that you’ll have to reference appState.value.user in updateState() instead.

Thanks a lot for your answer.

I edited a bit the code to show the blocks. By reading Mutables I understood that to access a mutable’s current value outside its defining block one needs to reference it directly. Only inside the defining block one needs variable.value.

Therefore, in code block 1 setState() needs to refer to appState.value whereas in code block 2 updateState() should refer directly to appState.user and not to appState.value.user.

Am I misunderstanding something?

Apologies, my answer was slightly off since I was thinking in Notebooks where mutables are set up differently.

In Framework, other blocks only have access to the mutable’s reactive value (a generator that yields a new value on every reassignment). In order to update the mutable you must use a setter that was defined in the same block as the mutable.

Likewise, if you want to access the non-reactive value you’d need to define a getter in the same block as the mutable. I would instead suggest to apply the classic pattern of passing the current state to a callback:

const appState = Mutable({/* ... */});
const setState = (callback) => appState.value = callback(appState.value);

Then call the setter like

function updateState(loggedIn) {
  setState(({user, ...state}) => ({...state, user: {...user, loggedIn}}));
  console.log(`state was updated`);
}

I apologize for still not getting it but can you please explain how your proposal will help break the loop?

  1. Your updateState function references appState, which is the Mutable’s reactive generator value.
  2. This reference causes the block that contains the updateState function to be invalidated/recomputed every time appState.value is reassigned.
  3. That in turn causes other blocks or interpolations that reference updateState to invalidate and rerun as well, which triggers the repeated calls in your third code block.

In your current code updateState essentially invalidates itself every time it is called, which causes the caller to get invalidated as well, triggering an endless loop.