本帖最后由 riyad 于 2025-2-22 20:09 编辑 6 s. ?5 [; s1 s* i4 y
! ]# ?' U! Q6 f7 h% N: a9 a我们在整个 @telegram-apps 软件包中使用的 signals 实现。 ) v C/ _3 q5 W6 |
安装pnpm
9 x, N9 Q d5 L) Q; z! e5 C9 j' G- pnpm i @telegram-apps/signals
复制代码 npm 4 n% N2 x1 U! t) r+ L
- npm i @telegram-apps/signals
复制代码 yarn ( p: |, K& }7 x# F! P0 _1 Z% N6 y9 O
- yarn add @telegram-apps/signals
' t- }: c2 t+ U4 ^" N
复制代码 / v+ Q. i6 k3 ` ~2 o! e2 G
Signalsignal 函数是最简单的 signal 构造函数,被其他软件包函数所使用。 要 创建新 signal,只需传递初始值即可: - import { signal } from '@telegram-apps/signals';
. O6 U4 \: ~2 f$ q - " `# _8 D6 d# Q4 o2 c
- const isVisible = signal(false);: Q8 Z; s- w2 t
- # b8 w" U3 J, `1 p
复制代码返回值代表一个具有实用方法的函数。 函数本身返回 当前信号值。 - console.log('The element is', isVisible() ? 'visible' : 'invisible');
9 @" h' P5 v/ l0 [
复制代码该函数还接受选项作为第二个参数。 开发人员可以指定 equals 函数,该函数接受当前值和输入值,如果认为它们相等,则返回 true, 。 + P/ j( J: R% p" ~* \
- const s = signal(10, {: X- }6 d* G: f) Y. r
- equals(current, next) {
# B3 O% M0 c8 N4 _- T! c) } - // Will not update the signal if the next value is
) r1 v% T+ y2 _ - // higher than the current one.
; G. `* Z0 E2 ?9 y: u3 s1 M - return next > current;; f2 W* y/ `" A6 I2 {" b
- }
5 j1 `" j% n! H- ~2 y0 M - });2 p" u7 g( s/ O+ `) ?( E7 X
- s.set(20); // will not update the signal
* C7 n* Q7 ?6 A& g# f - s.set(5); // will update the signal
复制代码 ! p0 W' k& ?- [8 S
set
7 m2 i" E J7 n1 k/ H要设置新值,请使用 set 方法: $ I8 B/ N8 R/ C# i" W
sub# r( H* i6 q% e! Q' ~* k
要跟踪信号变化,请使用 sub 方法。 它返回一个函数,用于移除绑定的 监听器。 监听器接受两个参数:当前值和上一个值。 - const removeListener = isVisible.sub((current, prev) => {
) W9 [) n& j4 q/ G: L2 R; P5 M - console.log('Value changed from', prev, 'to', current);
( F4 ~5 Q8 y. Z, H% l - });& D% G: H( F1 e `
1 d2 O. I% |) `- N* F- // Remove the listener whenever needed.& q& U' k# _6 L
- removeListener();
复制代码要只调用监听器一次,请使用第二个:
0 M+ \8 O X. m6 w- function listener(current: boolean, prev: boolean) {- x2 |1 i9 ^ z* V9 Z
- console.log('Value changed from', prev, 'to', current);) U* b1 A/ m k: i. a: |" V
- }
" j- X3 z8 [- c R
3 L6 o$ S4 O2 C0 S u2 q- isVisible.sub(listener, true);
* f) n1 f) `" b# p1 Q - // or
% R2 `2 t1 F7 j - isVisible.sub(listener, { once: true });
复制代码
9 d0 A1 @& c$ w: b1 p0 Z
0 e) q& ]. h S; @unsub% l% a3 n' S5 a# ~% F1 ]; L7 U3 ?
d- _- _) J8 m( S' g1 W
另外,要移除监听器,开发人员可以使用 unsub 方法: - function listener(current: boolean, prev: boolean) { w% j5 I7 R" I5 Q0 J
- console.log('Value changed from', prev, 'to', current);, D) |; o+ J3 e$ n- r. C
- }
/ M5 L* C r' L$ \* {& V9 P6 L6 r
6 `+ T$ w$ G0 i. a7 G( F8 T- isVisible.sub(listener);0 O, V7 [% o1 L4 b/ p
! }8 a$ Q1 w/ h( }1 Y a- // Remove the listener whenever needed., `" f% u9 u0 C: i
- isVisible.unsub(listener);
复制代码
7 O# U( ^/ F4 P9 S3 h5 \' Y& g1 Z' N
5 Q' L% a1 f; L2 l: T+ QunsubAll) |* t" Y1 N0 P; x8 c1 Y4 u
. Y' T4 [7 e) e- \2 W5 K K要移除所有监听器,请使用 unsubAll 方法: INFO 此方法不会移除计算信号添加的监听器。
- t& A! C& o* G% x( g& I: g% U W: t8 y' P' Q" {# i
reset
; i) T( s ~( }/ I. S6 k- N6 Y! w$ A0 P. A
要恢复到最初指定的值,请使用 reset 方法: - import { signal } from '@telegram-apps/signals'; x( g# d7 c; i2 ~5 t
- const isVisible = signal(false);
6 C- w3 a* e N3 ]. a0 L - isVisible.set(true); // isVisible becomes true o: Z# A8 r" J& O6 k
- isVisible.reset(); // isVisible becomes false again
复制代码
" t3 I4 t$ z+ E5 p. }% U& U G( Q5 S8 J* \7 c* E
destroy
. t$ \5 Y1 c$ J9 E) p
; g. z6 a3 V0 P! L当不再需要该信号且该信号没有被任何计算信号监听时,开发者 可以使用 destroy 方法强制移除所有监听者:
0 Z& s4 F( g" H. O& O6 O1 H; f; B; e8 t) j2 n( \
. O6 x6 R; R6 B" O+ B& V
Computed
/ H. M0 v4 |1 p7 F, N: U& V) W, x7 X8 ?
3 h& Z1 Y! l* [# L; ^2 Y4 }7 ucomputed 函数构建了一个计算 signal,当被调用signal的任何 发生变化时,该 signal 会自动重新计算。 这里有一个例子: - import { signal, computed } from '@telegram-apps/signals';* _+ S1 z R7 f- u; @
- ( |) u0 @. N( Z: ~9 }
- const a = signal(2);
2 R) a3 u! U! M0 K$ b - const b = signal(2);
/ r; ]1 I" D7 D8 A; b5 U" b - const sum = computed(() => a() + b()); // 4+ v: i d3 Q* e8 Q5 c/ S1 `8 n
4 x% N- O- d1 ] U/ r( [0 X- a.set(5); // sum becomes 7( u& t3 c* N5 v$ @% Y# |
- b.set(5); // sum becomes 10
复制代码返回值代表一个缺少 set 和 reset 方法的信号。 ' |$ e4 `. _) N, _6 N3 I7 d
批量更改batch 函数创建一个作用域,在此对 signal 突变进行批处理。 当开发人员希望防止计算 signal 在几个 相关 signal 连续变化时重新计算时,该功能非常有用。 - <blockquote><font size="3">import { signal, computed, batch } from '@telegram-apps/signals';) o" D& }3 t- z/ \; Q
1 p; n6 ]; ], j$ y2 _/ R$ f- const a = signal(1);
' `7 b7 A4 d$ m0 q( [* o( ~ - const b = signal(2);0 g. n- S$ D. Z* _
- const c = signal(3);
8 [3 ?6 Y' j* A5 l - const sum = computed(() => a() + b() + c()); // 66 r6 `, K' J/ u8 d% _
- m/ a% N: _, G" a# C# b( S- // Without batching, re-computation happens 3 times:( v8 U5 Y/ Y% u0 q8 b
- a.set(2); // sum recomputes and becomes 7
! M3 t L7 |) E) t1 E - b.set(3); // sum recomputes and becomes 8
2 s- `! _, m7 w% b( ~4 E - c.set(4); // sum recomputes and becomes 96 `/ ? v6 g" x7 |" v* |* P
0 Y1 y. n G6 |! p* y) z/ H5 o- // Reset each signal.
: V8 Q$ T& Y% P2 H! f$ e& m- y - a.reset();' y5 K. J, N' z0 `& {" |* o
- b.reset();7 ]: G; H0 @2 _# X! f2 Z8 X$ T
- c.reset();' e3 x& s3 b) g# n( C7 e
- // Note: reset calls the set method, which also causes
/ G/ o4 H: S8 R6 A6 L! L( M' z. {: p - // the sum signal to recompute.
) {& ~6 o# U0 c8 U - ! J3 x. B' p5 V& t6 C
- // Now, let's optimize using the batch function:
0 t+ j# x0 @$ b8 t0 V5 s - batch(() => {
: E, U4 W# y, B - a.set(2);
# |$ H1 `" I: u1 k' r - b.set(3);
% o u9 M# l' d/ K - c.set(4);
+ o2 V$ A M# p3 Q; y - });- T5 f% A5 O- D. J
- // At this point, sum will recompute only once because" ~: B3 h9 J, \) ^* x+ B0 f4 E3 Y- j' P
- // batch causes the sum signal to wait for the function to complete,8 X8 G2 v. y R+ ^
- // and then it triggers the recomputation.
% \( }6 Q6 P! @ - console.log(sum()); // 9</font>
复制代码
3 e1 h/ @& ]0 X3 I/ Q
3 |/ U( F( e6 o! P v- D, ]4 T" m6 O) W; l( \
- `, M1 D6 ~8 }3 N; q G) u; G. ?6 d7 C% G% V+ K5 ?: w
- S$ m, [$ T* g8 j7 I S1 x' m4 C
|