blob: 7860ab840bea322e2c4324d0b9a336eabe34cfef (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
package templ
import (
"context"
"io"
"sync/atomic"
)
// 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(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
// rendered once per context.
type OnceHandle struct {
// id is used to identify which instance of the OnceHandle is being used.
// The OnceHandle can't be an empty struct, because:
//
// | Two distinct zero-size variables may
// | have the same address in memory
//
// 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.
func (o *OnceHandle) Once() Component {
return ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
_, v := getContext(ctx)
if v.getHasBeenRendered(o) {
return nil
}
v.setHasBeenRendered(o)
if o.c != nil {
return o.c.Render(ctx, w)
}
return GetChildren(ctx).Render(ctx, w)
})
}
|