Skip to content

Conversation

@Gnyblast
Copy link

- Currently there's set,get, delete and observe method for statemanager
- Delete method even though it says halts the observations, it doesn't do it really
- I experienced it on a Rangeloop created component that interacts with confirmation dialog and observe state from there.
- Observation getting created when dialog was opened and I was deleting it on close, but it looks like they keep observing and interacting with multiple component same way was stacking up the obvervations.
- I implemented unobserve method to overcome this and it seems to work.
- This is pretty much `subscribe` and `unsubscribe` in angular.

    - Currently there's set,get, delete and observe method for statemanager
    - Delete method even though it says halts the observations, it doesn't do it really
    - I experienced it on a Rangeloop created component that interacts with confirmation dialog and observe state from there.
    - Observation getting created when dialog was opened and I was deleting it on close, but it looks like they keep observing and interacting with multiple component same way was stacking up the obvervations.
    - I implemented unobserve method to overcome this and it seems to work.
    - This is pretty much `subscribe` and `unsubscribe` in angular.
@maxence-charriere
Copy link
Owner

I what scenario would you need to unobserve a state?

@Gnyblast
Copy link
Author

Gnyblast commented Nov 11, 2025

Sure let me explain,

Let say I have a app-level confirmation dialog. These kind of things are generally injected only once to app and used ad-hoc.

So, imagine I have components that are generated with app.Range and each component has a button for an action that needs confirmation. So onclick to this button, I open the confirmation dialogs and setup an observeState with onclick, so I start listening what button is clicked in dialog modal through the statemanager. Let's say component X is clicked and opened dialog then set a observation then component Y then component Z. At the end when dialog opened by component Z is clicked, all X,Y,Z has a subscription to that state and gets notified and this might cause all of them to trigger action as each one has been clicked.

So in short, there are states in app-wise that should have only 1 single observers:

confirmation_dialog.go

func (c *ConfirmationDialog) OnMount(ctx app.Context) {
	var dialogState bool
	ctx.ObserveState("confirmation", &dialogState).OnChange(func() {
		if dialogState {
			c.openConfirmation(ctx)
		}
	})
}

func (c *ConfirmationDialog) openConfirmation(ctx app.Context) {
	doc := app.Window().Get("document")
	mdc := app.Window().Get("mdc")
	dialogElem := doc.Call("querySelector", "#confirmDialog")
	dialog := mdc.Get("dialog").Get("MDCDialog").New(dialogElem)
	c.onDialogClosing = app.FuncOf(func(this app.Value, args []app.Value) any {
		reason := args[0].Get("detail").Get("action").String()
		ctx.SetState("confirm_state", reason == "accept")
		dialogElem.Call("removeEventListener", "MDCDialog:closing", c.onDialogClosing)
		return nil
	})
	dialogElem.Call("addEventListener", "MDCDialog:closing", c.onDialogClosing)
	dialog.Call("open")
}

some_component.go

func (p *Pod) deallocate(ctx app.Context, e app.Event) {
	ctx.SetState("confirmation", true)
	var confirmState bool
	ctx.ObserveState("confirm_state", &confirmState).OnChange(func() {
		fmt.Println(confirmState)
		//TODO: Do deallocation
		ctx.UnObserveState("confirm_state")
	})
}

Otherwise it will cause many troubles in the app, and this is not just my idea, I used almost this type of subscriptions in many places especially angular. And all provides unsubscribe method.

@Gnyblast
Copy link
Author

@maxence-charriere any idea about this? Can it be achieved some other way?

@maxence-charriere
Copy link
Owner

So in short, there are states in app-wise that should have only 1 single observers

Maybe each button should have their own state.

@Gnyblast
Copy link
Author

So in short, there are states in app-wise that should have only 1 single observers

Maybe each button should have their own state.

If there are like 100 repetition of same component then it does not sound very practical to generate a unique observestate names for each honestly.

@maxence-charriere
Copy link
Owner

I think the interaction model becomes a lot simpler if each element manages its own confirmation flow. When you have a list of items and each one triggers a confirmation, the logic usually belongs to that specific element, the UI for that element should just react to its own state.

Right now you’re trying to coordinate multiple components through one shared global state, and that forces every element to subscribe/unsubscribe and stay in sync with one another. That’s where the complexity and the risk of mixing things together comes from.

If each element has its own state, you avoid multiple components listening to the same global key, and each one stays responsible for its own logic. The UI becomes a simple reaction to that state instead of a chain of state-based interactions across unrelated components.

@maxence-charriere
Copy link
Owner

Also, the way go-app is designed, a component automatically stops observing a state when it’s dismounted. So if each element owns its own confirmation state, you naturally avoid having stale observers or multiple listeners firing at the same time. The framework already handles the cleanup for you.

@maxence-charriere
Copy link
Owner

After that, I guess it doesn’t hurt to have a way to manually unobserve a state, but I’d rather avoid adding something that isn’t truly needed. Since go-app automatically stops observing when a component is dismounted, keeping the confirmation logic local to each element usually makes manual unsubscribe unnecessary. So if I add such a feature, I want to be sure it’s really required and not just working around a pattern that can be simplified.

@Gnyblast
Copy link
Author

Gnyblast commented Nov 21, 2025

Yes I think you are right but what makes me feel uncomfortable with each components with their own state name is: I fetch this datalist from a database table then, range loop iterates over and creates many of these components depending on response, to make things work, I need to write some overhead code and a small cache to generate random prefix/suffix for each state name and also store it to that cache to prevent name conflict. Because it's fully automatic and you don't know how many there will be of these components, it's then another automated process of keeping track of names. Apart from that, I don't want to insert hidden confirmation dialog component to the UI for each of these components. It creates overhead rendering process, instead 1 global confirmation dialog would release a lot of pressure on UI. Maybe I can get single confirmation dialog to work with many different state names, if I pass the target state name on opening, maybe I can get it works.

On the otherhand, I believe there will be need at somepoint for unobserving a state not that I'm having a scenario atm, but all these modern JS frameworks cannot be mistaken that it's implemented. I feel like there are exceptional cases that this might be needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants