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?
- Your
updateState
function references appState
, which is the Mutable’s reactive generator value.
- This reference causes the block that contains the
updateState
function to be invalidated/recomputed every time appState.value
is reassigned.
- 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.