English 简体中文 繁體中文 한국 사람 日本語 Deutsch русский بالعربية TÜRKÇE português คนไทย french

简体中文 繁體中文 English 日本語 Deutsch 한국 사람 بالعربية TÜRKÇE คนไทย Français русский

回答

收藏

Telegram 小程序 | TypeScript @telegram-apps/signals

开源社区 开源社区 9258 人阅读 | 0 人回复 | 2025-02-20

本帖最后由 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
  1. pnpm i @telegram-apps/signals
复制代码
npm " G% Z: ]; N! w% H. C  J# c& t+ |% K
  1. npm i @telegram-apps/signals
复制代码
yarn
! g: X3 ~; w& |' M( B
  1. yarn add @telegram-apps/signals
    ) Q6 _( G9 ?- |( N, r( U
复制代码
" ^1 m. m7 m1 r/ ]. M! I
Signal

signal 函数是最简单的 signal 构造函数,被其他软件包函数所使用。 要 创建新 signal,只需传递初始值即可:

  1. import { signal } from '@telegram-apps/signals';
    8 X) q9 M7 K8 d# b1 y
  2. & B! }* b& P% k4 D  L
  3. const isVisible = signal(false);
    ; r. ^, s' j: o: O0 d
  4. ; T; z1 V) Z/ W: K8 {/ H5 @
复制代码

返回值代表一个具有实用方法的函数。 函数本身返回 当前信号值。

  1. 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
  1. const s = signal(10, {
    7 X3 I/ o) W- f/ }% ?
  2.   equals(current, next) {, S4 O. S$ R1 @9 Z8 k1 m
  3.     // Will not update the signal if the next value is
    . g( s0 K2 N; C3 q& K' ]
  4.     // higher than the current one.
    ( S4 l4 l  }( }/ J6 {
  5.     return next > current;
      D; A0 w( z  b0 {4 A5 B! t
  6.   }
    . L; A, h% k2 r/ v$ H. m8 b! t, E
  7. });3 V$ c7 ^3 I# ?
  8. s.set(20); // will not update the signal7 y1 [6 ^+ A1 b" r
  9. s.set(5); // will update the signal
复制代码
0 U2 i( X( }1 d+ K
set2 ^1 n0 J9 g6 v; S, \4 W7 ^

要设置新值,请使用 set 方法:

  1. isVisible.set(true);
复制代码

. @! `  O3 m1 a; N4 b+ g  F
sub1 W" z) _" S% Z0 U. b1 e; D; u

要跟踪信号变化,请使用 sub 方法。 它返回一个函数,用于移除绑定的 监听器。 监听器接受两个参数:当前值和上一个值。

  1. const removeListener = isVisible.sub((current, prev) => {
    2 Y. v  C! V' v0 }
  2.   console.log('Value changed from', prev, 'to', current);
    # B& n+ C. @2 O, P- M
  3. });
    0 e% o, ?( h( _/ \' i2 n, I
  4. 1 A% O) i7 U5 j; Q7 G
  5. // Remove the listener whenever needed./ A4 N3 O& i. e4 A. l' h4 A  j; V
  6. removeListener();
复制代码

要只调用监听器一次,请使用第二个:


7 y/ @9 W$ G7 Q9 z, [9 U; {
  1. function listener(current: boolean, prev: boolean) {8 S7 A6 O/ [# h5 t
  2.   console.log('Value changed from', prev, 'to', current);
    8 Z" f, L: m: W$ c* f1 S7 r
  3. }$ N( C4 P4 Q8 B4 w* L

  4. ( N8 Y8 s! c. `. p9 u( R1 X. a9 D
  5. isVisible.sub(listener, true);* {1 n5 l% U- Y5 b  \+ R5 T
  6. // or
    7 g) ?- z2 C  i- x4 ^7 M! N& Z
  7. isVisible.sub(listener, { once: true });
复制代码

1 |/ T* T+ L9 R0 @. A
6 \" E/ S- x5 r$ r6 X
unsub
# X/ w/ E, }/ z3 N+ g5 x
; {, x. b( k* L& C: H. }/ ]9 m7 y( I

另外,要移除监听器,开发人员可以使用 unsub 方法:

  1. function listener(current: boolean, prev: boolean) {
    / W3 O# L9 w8 B8 F9 Q7 _" y! A" s+ C
  2.   console.log('Value changed from', prev, 'to', current);* u4 s' R- W7 w" _
  3. }
    9 T$ I$ h6 U6 h7 u
  4. . B$ F  P' b7 J) f
  5. isVisible.sub(listener);5 S9 I$ C' }0 c) Q/ g7 X# r
  6. $ E0 I. A4 d# }8 d+ ~8 e
  7. // Remove the listener whenever needed.
    4 l3 Z# C% a7 w* d
  8. isVisible.unsub(listener);
复制代码
' r0 t1 X6 g* v0 {7 `2 s8 `0 i1 l

# Z! l$ m6 Q. \2 [1 R
unsubAll6 m  O* U/ c  _& W7 R( Y) o2 M0 P- t
, ^; b8 t' i( e$ X' I7 N

要移除所有监听器,请使用 unsubAll 方法:

  1. isVisible.unsubAll();
复制代码

INFO

此方法不会移除计算信号添加的监听器。

  f# A2 \- z1 n" i/ y9 |

2 c: Y. e' p" i+ V3 s0 l* Q# J
reset
" x( W) Y. ~4 G: P3 x" g
+ L8 V3 _. [" S* \: ~' G

要恢复到最初指定的值,请使用 reset 方法:

  1. import { signal } from '@telegram-apps/signals';
    7 Q8 j! N2 ~  N/ z# v3 j* I
  2. const isVisible = signal(false);+ C7 t- S7 a6 |: P
  3. isVisible.set(true); // isVisible becomes true% _2 z/ r- J- a) W/ y
  4. 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 方法强制移除所有监听者:

  1. isVisible.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 会自动重新计算。

这里有一个例子:

  1. import { signal, computed } from '@telegram-apps/signals';
    4 P  k- l0 n3 h* E0 A

  2. 4 d2 z/ U. w% r; g$ M$ m( K
  3. const a = signal(2);* B2 t3 _( o: M- W
  4. const b = signal(2);
    : d' m* i  s) r4 t
  5. const sum = computed(() => a() + b()); // 4
    & L4 N- Q6 z7 v

  6. 9 t9 E- X( _- [7 T- V9 e
  7. a.set(5); // sum becomes 7: N' N" z, t, Y& L
  8. b.set(5); // sum becomes 10
复制代码

返回值代表一个缺少 set 和 reset 方法的信号。


, i( N% i; ~8 x; ~: _' s
批量更改

batch 函数创建一个作用域,在此对 signal 突变进行批处理。

当开发人员希望防止计算 signal 在几个 相关 signal 连续变化时重新计算时,该功能非常有用。

  1. <blockquote><font size="3">import { signal, computed, batch } from '@telegram-apps/signals';+ f6 A& D, F  t
  2. 0 ^5 g: \/ v+ P- C/ {6 c. X* g
  3. const a = signal(1);5 T# R, K! R$ l! ~
  4. const b = signal(2);
    6 ~. v! d* H; n' \# ]$ y6 C( j# u0 a
  5. const c = signal(3);
    , x4 q& b9 X9 p( L0 [
  6. const sum = computed(() => a() + b() + c()); // 6
    7 ]  ?! N7 V! X
  7. * _9 A6 n. P& _# P6 k/ G( m
  8. // Without batching, re-computation happens 3 times:" O( o( Y, {7 M: D
  9. a.set(2); // sum recomputes and becomes 7
    ( z7 z& B) E: x
  10. b.set(3); // sum recomputes and becomes 8& \  r- ~0 l* q( ~1 R* |" N
  11. c.set(4); // sum recomputes and becomes 99 u; ?6 X3 z- {8 D' u1 h9 H

  12. ) R3 N; N, I# A2 u) I" x9 [
  13. // Reset each signal.
    0 C; t; P6 i3 V% x. ?* m& X
  14. a.reset();$ R( D2 h! K8 v5 y: K
  15. b.reset();
    ) f6 ^- i4 T3 G9 K" J0 }9 }
  16. c.reset();; t+ C9 P. }6 L+ p0 s) |" E
  17. // Note: reset calls the set method, which also causes1 X/ ]" m* o3 F* y. ~% B3 k5 e
  18. // the sum signal to recompute.2 r( l- m. Z# T' d6 m  O: y

  19. + k* ?' a) n& a% B! l0 d
  20. // Now, let's optimize using the batch function:* C! Q$ \" g& C9 Y* M
  21. batch(() => {9 f# i( V- L6 y; V) R
  22.   a.set(2);
    # ^6 X1 i. E$ q4 `" w
  23.   b.set(3);7 e: T1 S( d' L/ Z. m: V5 Z  `
  24.   c.set(4);
    6 a7 ?9 V$ u2 I1 M9 y: U
  25. });
    ! k  t. v0 e7 l' b; @' h" j
  26. // At this point, sum will recompute only once because
    $ |- n) S) @4 v, I
  27. // batch causes the sum signal to wait for the function to complete,
    6 |- n$ j/ k1 F3 N: r& q9 L2 Z1 S
  28. // and then it triggers the recomputation., l" _& q8 `- Z, B
  29. 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
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则