本帖最后由 riyad 于 2025-2-22 20:09 编辑 $ I Z2 t* c2 q1 z z Q
. V3 }3 M! E7 V6 [5 {我们在整个 @telegram-apps 软件包中使用的 signals 实现。 " N: J. W* H( |9 h
安装pnpm 3 u3 z/ z- C6 _& P- l
- pnpm i @telegram-apps/signals
复制代码 npm
# C% ~$ ]2 F, I8 j9 V6 }1 V" |+ X- npm i @telegram-apps/signals
复制代码 yarn
( r7 s1 ` B0 y8 R" X2 @" g& V1 r- yarn add @telegram-apps/signals v" {. ]. O9 } Q
复制代码
8 n1 L) D9 r' HSignalsignal 函数是最简单的 signal 构造函数,被其他软件包函数所使用。 要 创建新 signal,只需传递初始值即可: - import { signal } from '@telegram-apps/signals';
0 a0 p S* T% s
( ~; M6 J& S) j+ C+ q. g# ]- const isVisible = signal(false);, p7 Z( ]# I, R# e) X% \/ T
7 a0 A! p7 E8 ^$ |
复制代码返回值代表一个具有实用方法的函数。 函数本身返回 当前信号值。 - console.log('The element is', isVisible() ? 'visible' : 'invisible');, {; i' h4 }" \8 h/ c4 {8 \
复制代码该函数还接受选项作为第二个参数。 开发人员可以指定 equals 函数,该函数接受当前值和输入值,如果认为它们相等,则返回 true, 。 - F( r" p, v9 ]6 g: J A* |( r5 t
- const s = signal(10, {) W8 Z9 ^: @0 y# B
- equals(current, next) {! n8 m2 {# A0 b4 K8 \) N
- // Will not update the signal if the next value is
! z8 R9 e: E1 Y! V. Z' R" B - // higher than the current one.
0 ?7 {0 K; k4 h - return next > current;( N1 R( f2 w7 r0 _$ h
- }
3 J s" h0 D `8 d - });
, ^( m5 i4 w8 w$ C* Y - s.set(20); // will not update the signal
- `2 K v6 B% l' \8 O% H - s.set(5); // will update the signal
复制代码 # x( ^8 c$ {! I& p! R2 a4 \
set
8 ~, D% A: u* U" P$ j: R) I要设置新值,请使用 set 方法:
1 J4 R* f5 _# |, I7 d1 E5 N+ Psub
) k- V% g3 P; }要跟踪信号变化,请使用 sub 方法。 它返回一个函数,用于移除绑定的 监听器。 监听器接受两个参数:当前值和上一个值。 - const removeListener = isVisible.sub((current, prev) => {
* }$ a& ?8 M, c3 @ - console.log('Value changed from', prev, 'to', current);. d" N2 A- ^% D+ B0 O, a; p
- });9 r9 D! j6 n# L, Q7 o: r% [6 M
* P- u5 v; _* W8 d& B$ m: U+ U- // Remove the listener whenever needed.
; N( o$ |4 h4 |3 V/ o - removeListener();
复制代码要只调用监听器一次,请使用第二个:
1 P! D+ Q" S' ~9 }- function listener(current: boolean, prev: boolean) {
! M) {$ e- m, h Y1 B! Y5 [7 | - console.log('Value changed from', prev, 'to', current);
; T% b0 q2 d4 f! v2 F8 B - }4 i" i( ?/ S( ]2 V8 I' s
& P: y+ t; t& u5 O: G- isVisible.sub(listener, true);
2 Z) v7 `- y& V0 y6 A - // or& F- i4 t# y6 l9 c; C6 x
- isVisible.sub(listener, { once: true });
复制代码
2 K/ L% v; e7 X- n _0 J8 p' D7 }0 h+ a4 Q& r! G& j: t
unsub
0 D% y& H7 M9 i. b: |; D
* n0 X& b' g, g8 M% @9 h: w另外,要移除监听器,开发人员可以使用 unsub 方法: - function listener(current: boolean, prev: boolean) {
}( y4 X5 a' o \+ }, a) n - console.log('Value changed from', prev, 'to', current);
* b+ @$ r- B& c/ W5 q - }
" \4 G9 G# h& ] - # i# @3 G# q% Y; y$ ]6 J }$ S) a
- isVisible.sub(listener);- R# V3 B! z* D$ V3 w" F
- ' p) d7 @+ P# y
- // Remove the listener whenever needed.# |. S/ u' w8 {9 w1 _" L
- isVisible.unsub(listener);
复制代码
( L& x/ v4 m$ |# v0 G! A0 u' N6 s; ?/ U: ]3 {/ O4 ~
unsubAll, ?- C! \( l2 i, s
* [* h- v; A: \9 ?0 s% s
要移除所有监听器,请使用 unsubAll 方法: INFO 此方法不会移除计算信号添加的监听器。
8 b( Q) ]1 D1 u( b9 ]
& \* `8 R# x% }4 ^reset
( [7 ~0 h J' Z) ~) L# ]
9 f. J" I+ e1 K' P! f1 C要恢复到最初指定的值,请使用 reset 方法: - import { signal } from '@telegram-apps/signals';: z# ] |9 u, P& ^& r4 @: X
- const isVisible = signal(false);4 I1 H p) w' X& d6 H, M
- isVisible.set(true); // isVisible becomes true
) C+ Q u z/ | - isVisible.reset(); // isVisible becomes false again
复制代码
" D5 ?/ U3 b) A N( q4 m& a6 s2 u2 K9 q- q
destroy
9 U- ?& x0 N7 c/ N: B/ G& v
0 y8 p1 J! A0 w# v0 x0 b当不再需要该信号且该信号没有被任何计算信号监听时,开发者 可以使用 destroy 方法强制移除所有监听者:
5 d. d- |8 d9 ~( F; p* q( \6 ]! k) o5 |9 Y1 t+ @2 h1 E: d, D
3 \, ^+ }) Z/ f; T1 xComputed( `/ |' g1 C a6 P/ p! A
* a* u* r. S% Ucomputed 函数构建了一个计算 signal,当被调用signal的任何 发生变化时,该 signal 会自动重新计算。 这里有一个例子: - import { signal, computed } from '@telegram-apps/signals';
: {$ U" {) H' x - 1 w g) w+ G/ f$ E0 n9 b
- const a = signal(2);
- @7 K9 |# {: @$ c. B1 p& s/ J9 C - const b = signal(2);
6 K5 f! |: U: \* l7 V. p - const sum = computed(() => a() + b()); // 4* U* a9 d1 o( M% o% j
& _, R! Z# Z ^- a.set(5); // sum becomes 7
8 [+ N8 o$ J2 C - b.set(5); // sum becomes 10
复制代码返回值代表一个缺少 set 和 reset 方法的信号。 & ~1 a8 Y0 E7 R1 f) E8 D. u
批量更改batch 函数创建一个作用域,在此对 signal 突变进行批处理。 当开发人员希望防止计算 signal 在几个 相关 signal 连续变化时重新计算时,该功能非常有用。 - <blockquote><font size="3">import { signal, computed, batch } from '@telegram-apps/signals';
" B8 T6 q) G. c; c1 g4 c* b: j! f - * D, B" l% j9 y; @+ Y
- const a = signal(1);
; X# D2 B0 H9 M* s5 G& ^2 H - const b = signal(2);
$ }6 ?$ U5 y5 `8 v9 c, V2 U - const c = signal(3);" c$ `& `- `8 X
- const sum = computed(() => a() + b() + c()); // 65 ~& t. }7 s% W0 t) |7 y
" W1 ~$ o( {/ c7 W3 X& ]- // Without batching, re-computation happens 3 times:9 k7 s9 d% K' r' C4 x/ h7 @
- a.set(2); // sum recomputes and becomes 7
) I2 L" z* n9 v' L z - b.set(3); // sum recomputes and becomes 8% k1 Z* M7 Y- b! X5 g# w) N
- c.set(4); // sum recomputes and becomes 96 C4 }- u. D2 x: c
- 0 y* ~# M- U0 c- R T7 l
- // Reset each signal.
) T1 ?7 k; ?& H - a.reset();% C" K* Q# M9 J' l& }2 v2 |
- b.reset();
7 k7 Q& {9 n8 p, j - c.reset();$ A8 x. c- R) y- a4 [ @
- // Note: reset calls the set method, which also causes
0 X, G% I9 i4 o. ~% i - // the sum signal to recompute.
' f0 y0 r, Q9 \: A3 G
& q) }6 M% N! L- // Now, let's optimize using the batch function:( @, {) W0 E S5 k" }4 g/ R9 U/ o
- batch(() => {! U. ?5 H3 V" z6 r9 X3 L
- a.set(2);& }' L1 z( y4 J; u1 _
- b.set(3);, H0 L3 V( K! ^% i, k, v
- c.set(4);
! d G, T% W5 W; E% z0 D ~* o! Q; c - });6 U2 F( C5 W p0 l1 D1 Y' `
- // At this point, sum will recompute only once because
# u/ v: N( E& F' K - // batch causes the sum signal to wait for the function to complete,
) z3 x- n+ H& y7 R# ]* O - // and then it triggers the recomputation.+ @' L0 N2 F2 |4 J
- console.log(sum()); // 9</font>
复制代码
. R% {; P& `9 [* M7 E% t$ N $ a. X4 m6 o6 ?
6 [, A( s! A+ O4 L$ c9 H& e
8 w6 _- p/ Y1 o" Z
C0 t! X; ^1 ]/ T# v% j8 L6 Y$ C4 i; ` t9 K+ W; P7 O
|