本帖最后由 riyad 于 2025-2-22 20:09 编辑
0 o3 M$ l) m* I
# c" e" v5 J& a- m5 r9 h我们在整个 @telegram-apps 软件包中使用的 signals 实现。
. A( B1 ]" o5 F% w# I8 h% r0 u安装pnpm
! N/ [9 n9 _1 d0 F& t- pnpm i @telegram-apps/signals
复制代码 npm 9 C# P' G% d/ K
- npm i @telegram-apps/signals
复制代码 yarn % Z1 A7 G4 s6 s
- yarn add @telegram-apps/signals
$ {" \" n( O1 K, d: m
复制代码 & w" M5 @* ^; [$ C( D
Signalsignal 函数是最简单的 signal 构造函数,被其他软件包函数所使用。 要 创建新 signal,只需传递初始值即可: - import { signal } from '@telegram-apps/signals';
# K/ M! _+ P, N6 G! ]; {" ^
& j# u- k6 g4 u' J- \( }$ U- const isVisible = signal(false);
9 b* F% }& E0 N - : S1 \; l" ?8 N4 M- A3 T( d
复制代码返回值代表一个具有实用方法的函数。 函数本身返回 当前信号值。 - console.log('The element is', isVisible() ? 'visible' : 'invisible');+ ?' h5 N* \" N' D: \
复制代码该函数还接受选项作为第二个参数。 开发人员可以指定 equals 函数,该函数接受当前值和输入值,如果认为它们相等,则返回 true, 。
# \( q _ E/ C" b5 h" s/ C, v3 H- const s = signal(10, {, O. K; r s+ U, R+ C/ A8 D8 H% \
- equals(current, next) {
/ y# u) Z) N1 {* X: | - // Will not update the signal if the next value is% ]) D- d$ |6 a: v9 {( Y% E
- // higher than the current one.- u* D8 b% e9 j) a+ h) }/ U
- return next > current;* n! l7 f, A: B+ F$ g6 I% M
- }3 n5 z: w) Y2 t5 e
- });
( b3 i) X7 \+ n' \( F: @1 A - s.set(20); // will not update the signal: Y8 X- f: T9 H* }
- s.set(5); // will update the signal
复制代码 $ y% g/ C( u5 w* m' A
set8 J! F0 p: K( \4 P
要设置新值,请使用 set 方法: 3 Q( @! i* U; u$ u, b, U! h; u' r8 k
sub6 n/ d' g9 k5 x: X+ [
要跟踪信号变化,请使用 sub 方法。 它返回一个函数,用于移除绑定的 监听器。 监听器接受两个参数:当前值和上一个值。 - const removeListener = isVisible.sub((current, prev) => {7 ]5 U2 `& L) t" F% c& Y0 \
- console.log('Value changed from', prev, 'to', current);) s+ i; c$ \2 ~
- });. ]4 r+ h9 `6 ^) D' I, l
9 T, q; E0 S: s6 K3 L- b a N- // Remove the listener whenever needed.6 b6 O& x% v2 `) Y
- removeListener();
复制代码要只调用监听器一次,请使用第二个: 6 m8 \5 B6 ~# F* v4 x; P, b& Z7 y' E
- function listener(current: boolean, prev: boolean) {: l9 T2 b5 O3 R0 \9 a, Y+ K6 z
- console.log('Value changed from', prev, 'to', current);% `+ x0 N! y& N q2 M
- }. W5 {9 \, G+ p, O; J
- ) f" \& H; I) `0 P
- isVisible.sub(listener, true);
( H0 n) O4 h; X2 e) [1 I - // or* P( Z, \6 K( k* d3 L( G
- isVisible.sub(listener, { once: true });
复制代码
" `7 K6 S6 y; Z4 W" a2 p# U# [
) k4 l5 b9 z3 tunsub
6 ~) K! |4 B% O
- Q: \# c, ^1 u3 e; r' Y另外,要移除监听器,开发人员可以使用 unsub 方法: - function listener(current: boolean, prev: boolean) {; f9 w, F! s. O# i
- console.log('Value changed from', prev, 'to', current);. C; j! K# v4 k" S: {
- }2 V# [9 X9 g" O Y
- k$ C( [! M$ q$ B$ h1 Y
- isVisible.sub(listener);
& ^* F' v' w; X1 r. j! N+ k5 j, w - ; d3 @3 J6 m9 v
- // Remove the listener whenever needed.$ K5 C' I2 K& ~# B0 t% l
- isVisible.unsub(listener);
复制代码
$ O6 I. I- v5 T/ W4 [+ W1 m9 s2 j1 h- E; g) M$ E
unsubAll
9 L. Y. G! \. x2 d
9 F% s2 S. `. b- A. K# b+ I& d要移除所有监听器,请使用 unsubAll 方法: INFO 此方法不会移除计算信号添加的监听器。
8 A9 d8 A1 f& b2 m
Q4 F- H7 m" F/ m8 `reset
+ b8 R# U( j! I4 k8 z
" g0 x7 W E7 k0 e* H6 B# G要恢复到最初指定的值,请使用 reset 方法: - import { signal } from '@telegram-apps/signals';
# n) e# ^* |4 K4 N& J - const isVisible = signal(false);$ |( q9 V# D8 o; o
- isVisible.set(true); // isVisible becomes true% w; c. K2 y0 c& a& n8 `
- isVisible.reset(); // isVisible becomes false again
复制代码 3 |- d: P& Y7 t6 i
4 y2 k3 U1 j9 h" Ddestroy+ ]+ L g5 O# @. Y) V+ U9 l
; R$ i. Y1 k7 A, T9 s1 G当不再需要该信号且该信号没有被任何计算信号监听时,开发者 可以使用 destroy 方法强制移除所有监听者: 3 X1 l7 @1 w8 h }7 H1 G) K6 Q
. ]9 r0 x( H* _
% p: ^/ \% I! d+ x8 j
Computed8 j: o, ?% w( q& v- U2 O" [
1 @& H, x. F! E5 {/ o0 d8 e% w
computed 函数构建了一个计算 signal,当被调用signal的任何 发生变化时,该 signal 会自动重新计算。 这里有一个例子: - import { signal, computed } from '@telegram-apps/signals';
2 ?! k* W H4 [" o; z# t- R/ e - % s, K& g& o o
- const a = signal(2);* G5 b, J2 _& o9 K
- const b = signal(2);
$ ?& p, {1 M; Q5 s8 \+ B - const sum = computed(() => a() + b()); // 42 b$ n" D( B+ K* }' q0 G% k I
- / A! }4 Q. @& i7 U
- a.set(5); // sum becomes 7: r' Z0 c$ S" d: ^% A
- b.set(5); // sum becomes 10
复制代码返回值代表一个缺少 set 和 reset 方法的信号。
1 ]4 X7 n; j# H- v0 q批量更改batch 函数创建一个作用域,在此对 signal 突变进行批处理。 当开发人员希望防止计算 signal 在几个 相关 signal 连续变化时重新计算时,该功能非常有用。 - <blockquote><font size="3">import { signal, computed, batch } from '@telegram-apps/signals';
4 e( h4 D3 I# h0 T5 v3 h/ D* v3 Y+ q
; f# V) Z1 ]/ u8 l4 F* x5 N; ~0 I9 }! f- const a = signal(1);
5 I B/ c& i- ]# h& { - const b = signal(2);
; D$ C! A* I( }6 v$ B9 i6 I - const c = signal(3);
! @* P3 f+ N+ I - const sum = computed(() => a() + b() + c()); // 6
3 T% ?# U3 U B7 Q - 2 K4 e: j' K% y6 S0 n
- // Without batching, re-computation happens 3 times:
! J! w8 p! N3 V& l) C3 r' e& l - a.set(2); // sum recomputes and becomes 7
# V0 n0 k; f0 y. r; n6 K, T# o1 g - b.set(3); // sum recomputes and becomes 8 R7 \8 S+ }) k0 ?# h s9 L
- c.set(4); // sum recomputes and becomes 9) Z5 }: ^$ E8 J. O; J4 F) @
- 7 b+ O1 D3 z. D3 }6 v% o
- // Reset each signal.
5 t+ H. P2 A' X5 f1 ~/ M6 ~ - a.reset();/ S, {% S! v8 A: l! f4 W
- b.reset();. {$ B0 G, ]" n; ^2 L- c+ @
- c.reset();) M- s2 i0 G1 z. D
- // Note: reset calls the set method, which also causes
- [) \5 W$ G ~ p - // the sum signal to recompute.
/ n5 P0 J' t( \
/ r- P( a, k) \% C4 u. b- // Now, let's optimize using the batch function:
$ f; x) n2 d. U - batch(() => {" `$ i# U8 w3 ?; S' E
- a.set(2);
! t8 e" [) X0 |+ n7 i - b.set(3);+ ?; O0 ^- T7 K
- c.set(4);& K! g9 p! j& C5 H# @# T
- });4 \) K8 ]! I# D
- // At this point, sum will recompute only once because9 N5 e5 I$ l* N; }7 [0 u( a
- // batch causes the sum signal to wait for the function to complete,
8 I) Q+ p* v7 `# Q% w - // and then it triggers the recomputation.
4 s& K" L, T( S3 S! y - console.log(sum()); // 9</font>
复制代码
! I2 I/ W9 `: l% F0 e: e$ G2 s
& c# s! _9 p3 w( m' i5 j% x+ G5 `- t1 Q5 C9 l( G/ O& Y) V
% X: r; m% Y! c; _. Z5 _4 C
- p( x5 q& d- ^
: e. K' [* V, p' i% }2 j1 f |