bubbletea icon indicating copy to clipboard operation
bubbletea copied to clipboard

Pass Context to Init?

Open joshfrench opened this issue 2 years ago • 3 comments

I have a use case like the HTTP example, except the external client expects a context:

type Client interface {
  Call(context.Context)
}

type model struct {
  client Client
}

func (m model) Init() {
  m.client.Call( ¯\_(ツ)_/¯ )
}

What's the "right" way to structure this? I found tea.WithContext but it's not clear if or how I can actually access the program's context elsewhere. I could just do this with a channel (like the realtime example) or perhaps a closure, but I'm curious if there's a pattern you like for this kind of thing.

Thanks!

joshfrench avatar May 31 '23 23:05 joshfrench

tea.WithContext returns a ProgramOption and is intended for you to provide a context to Bubbletea if say, you wanted to ability to cancel execution of the application externally:

p := tea.NewProgram(app, tea.WithContext(ctx))

Bubbletea doesn't prescribe a way for you to provide context inside an Init handler, so it's up to you to create one depending on your use-case. It's probably desirable for have a new context for each data fetch anyway, so your code could look like this for example:

type model struct {
	client Client
	ctx context.Context
}

func (m model) Init() {
	ctx, cancel := context.WithTimeout(m.ctx, 30 * time.Second)
	defer cancel()
	m.client.Call(ctx)
}

drakenstar avatar Jul 29 '23 13:07 drakenstar

Regarding the above example:

type model struct {
	client Client
	ctx context.Context
}

Please note that context documentation suggests to avoid storing contexts inside structs:

Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it.

Edit: see also blog post with more information regarding storing contexts in structs.

naglis avatar Aug 11 '23 21:08 naglis