本帖最后由 riyad 于 2025-2-22 20:09 编辑
" r# Z# W' \$ K/ M3 S
6 m3 s; N4 j3 |* B( j3 j6 e8 c我们在整个 @telegram-apps 软件包中使用的 signals 实现。 - Z% A9 [3 @* X. c# x: f
安装pnpm r. Q6 O1 o1 ?$ H+ ]' s9 u# v
- pnpm i @telegram-apps/signals
复制代码 npm " G% Z: ]; N! w% H. C J# c& t+ |% K
- npm i @telegram-apps/signals
复制代码 yarn
! g: X3 ~; w& |' M( B- yarn add @telegram-apps/signals
) Q6 _( G9 ?- |( N, r( U
复制代码 " ^1 m. m7 m1 r/ ]. M! I
Signalsignal 函数是最简单的 signal 构造函数,被其他软件包函数所使用。 要 创建新 signal,只需传递初始值即可: - import { signal } from '@telegram-apps/signals';
8 X) q9 M7 K8 d# b1 y - & B! }* b& P% k4 D L
- const isVisible = signal(false);
; r. ^, s' j: o: O0 d - ; T; z1 V) Z/ W: K8 {/ H5 @
复制代码返回值代表一个具有实用方法的函数。 函数本身返回 当前信号值。 - console.log('The element is', isVisible() ? 'visible' : 'invisible');
. j1 S1 g0 m# Q6 t% q r
复制代码该函数还接受选项作为第二个参数。 开发人员可以指定 equals 函数,该函数接受当前值和输入值,如果认为它们相等,则返回 true, 。
6 o6 ^/ r2 V3 f1 H3 p% u7 V9 C1 w- const s = signal(10, {
7 X3 I/ o) W- f/ }% ? - equals(current, next) {, S4 O. S$ R1 @9 Z8 k1 m
- // Will not update the signal if the next value is
. g( s0 K2 N; C3 q& K' ] - // higher than the current one.
( S4 l4 l }( }/ J6 { - return next > current;
D; A0 w( z b0 {4 A5 B! t - }
. L; A, h% k2 r/ v$ H. m8 b! t, E - });3 V$ c7 ^3 I# ?
- s.set(20); // will not update the signal7 y1 [6 ^+ A1 b" r
- s.set(5); // will update the signal
复制代码 0 U2 i( X( }1 d+ K
set2 ^1 n0 J9 g6 v; S, \4 W7 ^
要设置新值,请使用 set 方法:
. @! ` O3 m1 a; N4 b+ g Fsub1 W" z) _" S% Z0 U. b1 e; D; u
要跟踪信号变化,请使用 sub 方法。 它返回一个函数,用于移除绑定的 监听器。 监听器接受两个参数:当前值和上一个值。 - const removeListener = isVisible.sub((current, prev) => {
2 Y. v C! V' v0 } - console.log('Value changed from', prev, 'to', current);
# B& n+ C. @2 O, P- M - });
0 e% o, ?( h( _/ \' i2 n, I - 1 A% O) i7 U5 j; Q7 G
- // Remove the listener whenever needed./ A4 N3 O& i. e4 A. l' h4 A j; V
- removeListener();
复制代码要只调用监听器一次,请使用第二个:
7 y/ @9 W$ G7 Q9 z, [9 U; {- function listener(current: boolean, prev: boolean) {8 S7 A6 O/ [# h5 t
- console.log('Value changed from', prev, 'to', current);
8 Z" f, L: m: W$ c* f1 S7 r - }$ N( C4 P4 Q8 B4 w* L
( N8 Y8 s! c. `. p9 u( R1 X. a9 D- isVisible.sub(listener, true);* {1 n5 l% U- Y5 b \+ R5 T
- // or
7 g) ?- z2 C i- x4 ^7 M! N& Z - isVisible.sub(listener, { once: true });
复制代码
1 |/ T* T+ L9 R0 @. A
6 \" E/ S- x5 r$ r6 Xunsub
# X/ w/ E, }/ z3 N+ g5 x
; {, x. b( k* L& C: H. }/ ]9 m7 y( I另外,要移除监听器,开发人员可以使用 unsub 方法: - function listener(current: boolean, prev: boolean) {
/ W3 O# L9 w8 B8 F9 Q7 _" y! A" s+ C - console.log('Value changed from', prev, 'to', current);* u4 s' R- W7 w" _
- }
9 T$ I$ h6 U6 h7 u - . B$ F P' b7 J) f
- isVisible.sub(listener);5 S9 I$ C' }0 c) Q/ g7 X# r
- $ E0 I. A4 d# }8 d+ ~8 e
- // Remove the listener whenever needed.
4 l3 Z# C% a7 w* d - isVisible.unsub(listener);
复制代码 ' r0 t1 X6 g* v0 {7 `2 s8 `0 i1 l
# Z! l$ m6 Q. \2 [1 RunsubAll6 m O* U/ c _& W7 R( Y) o2 M0 P- t
, ^; b8 t' i( e$ X' I7 N
要移除所有监听器,请使用 unsubAll 方法: INFO 此方法不会移除计算信号添加的监听器。 f# A2 \- z1 n" i/ y9 |
2 c: Y. e' p" i+ V3 s0 l* Q# Jreset
" x( W) Y. ~4 G: P3 x" g
+ L8 V3 _. [" S* \: ~' G要恢复到最初指定的值,请使用 reset 方法: - import { signal } from '@telegram-apps/signals';
7 Q8 j! N2 ~ N/ z# v3 j* I - const isVisible = signal(false);+ C7 t- S7 a6 |: P
- isVisible.set(true); // isVisible becomes true% _2 z/ r- J- a) W/ y
- isVisible.reset(); // isVisible becomes false again
复制代码
) p- N4 {" }( X2 F5 A/ X- M4 P7 ?$ G j# w+ a9 \
destroy
, ], @4 T* T& B; M( p- ^7 Q' [ m: q3 c
当不再需要该信号且该信号没有被任何计算信号监听时,开发者 可以使用 destroy 方法强制移除所有监听者: % x1 n' d% m" Y; `
0 c" Y x' m5 N+ f$ U& K% s$ z9 L1 ~' P0 f$ `3 y$ l" z- y) Z( V
Computed7 T! G( \, [0 s! H M" _9 F
4 w, s4 M( r+ A1 s$ v
computed 函数构建了一个计算 signal,当被调用signal的任何 发生变化时,该 signal 会自动重新计算。 这里有一个例子: - import { signal, computed } from '@telegram-apps/signals';
4 P k- l0 n3 h* E0 A
4 d2 z/ U. w% r; g$ M$ m( K- const a = signal(2);* B2 t3 _( o: M- W
- const b = signal(2);
: d' m* i s) r4 t - const sum = computed(() => a() + b()); // 4
& L4 N- Q6 z7 v
9 t9 E- X( _- [7 T- V9 e- a.set(5); // sum becomes 7: N' N" z, t, Y& L
- b.set(5); // sum becomes 10
复制代码返回值代表一个缺少 set 和 reset 方法的信号。
, i( N% i; ~8 x; ~: _' s批量更改batch 函数创建一个作用域,在此对 signal 突变进行批处理。 当开发人员希望防止计算 signal 在几个 相关 signal 连续变化时重新计算时,该功能非常有用。 - <blockquote><font size="3">import { signal, computed, batch } from '@telegram-apps/signals';+ f6 A& D, F t
- 0 ^5 g: \/ v+ P- C/ {6 c. X* g
- const a = signal(1);5 T# R, K! R$ l! ~
- const b = signal(2);
6 ~. v! d* H; n' \# ]$ y6 C( j# u0 a - const c = signal(3);
, x4 q& b9 X9 p( L0 [ - const sum = computed(() => a() + b() + c()); // 6
7 ] ?! N7 V! X - * _9 A6 n. P& _# P6 k/ G( m
- // Without batching, re-computation happens 3 times:" O( o( Y, {7 M: D
- a.set(2); // sum recomputes and becomes 7
( z7 z& B) E: x - b.set(3); // sum recomputes and becomes 8& \ r- ~0 l* q( ~1 R* |" N
- c.set(4); // sum recomputes and becomes 99 u; ?6 X3 z- {8 D' u1 h9 H
) R3 N; N, I# A2 u) I" x9 [- // Reset each signal.
0 C; t; P6 i3 V% x. ?* m& X - a.reset();$ R( D2 h! K8 v5 y: K
- b.reset();
) f6 ^- i4 T3 G9 K" J0 }9 } - c.reset();; t+ C9 P. }6 L+ p0 s) |" E
- // Note: reset calls the set method, which also causes1 X/ ]" m* o3 F* y. ~% B3 k5 e
- // the sum signal to recompute.2 r( l- m. Z# T' d6 m O: y
+ k* ?' a) n& a% B! l0 d- // Now, let's optimize using the batch function:* C! Q$ \" g& C9 Y* M
- batch(() => {9 f# i( V- L6 y; V) R
- a.set(2);
# ^6 X1 i. E$ q4 `" w - b.set(3);7 e: T1 S( d' L/ Z. m: V5 Z `
- c.set(4);
6 a7 ?9 V$ u2 I1 M9 y: U - });
! k t. v0 e7 l' b; @' h" j - // At this point, sum will recompute only once because
$ |- n) S) @4 v, I - // batch causes the sum signal to wait for the function to complete,
6 |- n$ j/ k1 F3 N: r& q9 L2 Z1 S - // and then it triggers the recomputation., l" _& q8 `- Z, B
- console.log(sum()); // 9</font>
复制代码
, ]% @# a. J6 H) e% N$ D( y. y
" W/ \/ y7 R/ N( }0 s. P) \- C r; S# |+ x% \" e" N
3 D; e) l0 @/ d) F Z
/ J& T5 f7 y w. s& ?8 U8 p7 |
' o* D7 V# F% c) L# Q |