1
- import { DestroyRef , Injector , inject } from '@angular/core' ;
1
+ import { DestroyRef , effect , inject , Injector } from '@angular/core' ;
2
2
import { assertInjector } from 'ngxtension/assert-injector' ;
3
3
import { injectStore } from '../store' ;
4
4
import type { NgtBeforeRenderRecord } from '../types' ;
@@ -7,35 +7,41 @@ import type { NgtBeforeRenderRecord } from '../types';
7
7
* `injectBeforeRender` invokes its callback on every frame. Hence, the notion of tracking
8
8
* changes (i.e: signals) does not really matter since we're getting latest values of the things we need on every frame anyway.
9
9
*
10
- * If `priority` is dynamic, consumers should set up `injectBeforeRender` in
11
- * an `effect` and track `priority` changes. Make use of `onCleanup` to clean up
12
- * previous before render subscription
10
+ * If `priority` is a Signal, `injectBeforeRender` will set up an Effect internally and returns the `EffectRef#destroy` instead.
13
11
*
14
12
* @example
15
13
* ```ts
16
- * const injector = inject(Injector);
17
- *
18
- * effect((onCleanup) => {
19
- * const priority = this.priority(); // track priority
20
- *
21
- * const sub = injectBeforeRender(
22
- * ({ gl, camera }) => {
23
- * // before render logic
24
- * },
25
- * {
26
- * priority,
27
- * injector, // injector is needed since injectBeforeRender is invoked in effect body
28
- * }
29
- * });
30
- *
31
- * onCleanup(() => sub());
32
- * });
14
+ * const destroy = injectBeforeRender(
15
+ * ({ gl, camera }) => {
16
+ * // before render logic
17
+ * },
18
+ * {
19
+ * priority: this.priority, // this.priority is a Signal<number>
20
+ * }
21
+ * )
33
22
* ```
34
23
*/
35
24
export function injectBeforeRender (
36
25
cb : NgtBeforeRenderRecord [ 'callback' ] ,
37
- { priority = 0 , injector } : { priority ?: number ; injector ?: Injector } = { } ,
26
+ { priority = 0 , injector } : { priority ?: number | ( ( ) => number ) ; injector ?: Injector } = { } ,
38
27
) {
28
+ if ( typeof priority === 'function' ) {
29
+ const effectRef = assertInjector ( injectBeforeRender , injector , ( ) => {
30
+ const store = injectStore ( ) ;
31
+ const ref = effect ( ( onCleanup ) => {
32
+ const p = priority ( ) ;
33
+ const sub = store . snapshot . internal . subscribe ( cb , p , store ) ;
34
+ onCleanup ( ( ) => sub ( ) ) ;
35
+ } ) ;
36
+
37
+ inject ( DestroyRef ) . onDestroy ( ( ) => void ref . destroy ( ) ) ;
38
+
39
+ return ref ;
40
+ } ) ;
41
+
42
+ return effectRef . destroy . bind ( effectRef ) ;
43
+ }
44
+
39
45
return assertInjector ( injectBeforeRender , injector , ( ) => {
40
46
const store = injectStore ( ) ;
41
47
const sub = store . snapshot . internal . subscribe ( cb , priority , store ) ;
0 commit comments