diff --git a/.version b/.version index b4cddf5b1..1fc2434fa 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -0.2.702 \ No newline at end of file +0.2.705 \ No newline at end of file diff --git a/once.go b/once.go index a69d0b20e..7860ab840 100644 --- a/once.go +++ b/once.go @@ -9,12 +9,27 @@ import ( // onceHandleIndex is used to identify unique once handles in a program run. var onceHandleIndex int64 +type OnceOpt func(*OnceHandle) + +// WithOnceComponent sets the component to be rendered once per context. +// This can be used instead of setting the children of the `Once` method, +// for example, if creating a code component outside of a templ HTML template. +func WithComponent(c Component) OnceOpt { + return func(o *OnceHandle) { + o.c = c + } +} + // NewOnceHandle creates a OnceHandle used to ensure that the children of its // `Once` method are only rendered once per context. -func NewOnceHandle() *OnceHandle { - return &OnceHandle{ +func NewOnceHandle(opts ...OnceOpt) *OnceHandle { + oh := &OnceHandle{ id: atomic.AddInt64(&onceHandleIndex, 1), } + for _, opt := range opts { + opt(oh) + } + return oh } // OnceHandle is used to ensure that the children of its `Once` method are are only @@ -28,6 +43,9 @@ type OnceHandle struct { // // https://go.dev/ref/spec#Size_and_alignment_guarantees id int64 + // c is the component to be rendered once per context. + // if c is nil, the children of the `Once` method are rendered. + c Component } // Once returns a component that renders its children once per context. @@ -38,6 +56,9 @@ func (o *OnceHandle) Once() Component { return nil } v.setHasBeenRendered(o) + if o.c != nil { + return o.c.Render(ctx, w) + } return GetChildren(ctx).Render(ctx, w) }) } diff --git a/once_test.go b/once_test.go index c2681be30..bd48da3a3 100644 --- a/once_test.go +++ b/once_test.go @@ -103,4 +103,15 @@ func TestOnceHandle(t *testing.T) { t.Errorf("unexpected diff:\n%v", diff) } }) + t.Run("a handle can be used to render a specific component", func(t *testing.T) { + ctx := templ.WithChildren(context.Background(), templ.Raw("child")) + o := templ.NewOnceHandle(templ.WithComponent(templ.Raw("c"))).Once() + var w strings.Builder + if err := o.Render(ctx, &w); err != nil { + t.Fatalf("unexpected error: %v", err) + } + if diff := cmp.Diff("c", w.String()); diff != "" { + t.Errorf("unexpected diff:\n%v", diff) + } + }) }