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

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

回答

收藏

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

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

本帖最后由 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
  1. pnpm i @telegram-apps/signals
复制代码
npm 4 n% N2 x1 U! t) r+ L
  1. npm i @telegram-apps/signals
复制代码
yarn ( p: |, K& }7 x# F! P0 _1 Z% N6 y9 O
  1. yarn add @telegram-apps/signals
    ' t- }: c2 t+ U4 ^" N
复制代码
/ v+ Q. i6 k3 `  ~2 o! e2 G
Signal

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

  1. import { signal } from '@telegram-apps/signals';
    . O6 U4 \: ~2 f$ q
  2. " `# _8 D6 d# Q4 o2 c
  3. const isVisible = signal(false);: Q8 Z; s- w2 t
  4. # b8 w" U3 J, `1 p
复制代码

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

  1. console.log('The element is', isVisible() ? 'visible' : 'invisible');
    9 @" h' P5 v/ l0 [
复制代码

该函数还接受选项作为第二个参数。 开发人员可以指定 equals 函数,该函数接受当前值和输入值,如果认为它们相等,则返回 true, 。

+ P/ j( J: R% p" ~* \
  1. const s = signal(10, {: X- }6 d* G: f) Y. r
  2.   equals(current, next) {
    # B3 O% M0 c8 N4 _- T! c) }
  3.     // Will not update the signal if the next value is
    ) r1 v% T+ y2 _
  4.     // higher than the current one.
    ; G. `* Z0 E2 ?9 y: u3 s1 M
  5.     return next > current;; f2 W* y/ `" A6 I2 {" b
  6.   }
    5 j1 `" j% n! H- ~2 y0 M
  7. });2 p" u7 g( s/ O+ `) ?( E7 X
  8. s.set(20); // will not update the signal
    * C7 n* Q7 ?6 A& g# f
  9. s.set(5); // will update the signal
复制代码
! p0 W' k& ?- [8 S
set
7 m2 i" E  J7 n1 k/ H

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

  1. isVisible.set(true);
复制代码
$ I8 B/ N8 R/ C# i" W
sub# r( H* i6 q% e! Q' ~* k

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

  1. const removeListener = isVisible.sub((current, prev) => {
    ) W9 [) n& j4 q/ G: L2 R; P5 M
  2.   console.log('Value changed from', prev, 'to', current);
    ( F4 ~5 Q8 y. Z, H% l
  3. });& D% G: H( F1 e  `

  4. 1 d2 O. I% |) `- N* F
  5. // Remove the listener whenever needed.& q& U' k# _6 L
  6. removeListener();
复制代码

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


0 M+ \8 O  X. m6 w
  1. function listener(current: boolean, prev: boolean) {- x2 |1 i9 ^  z* V9 Z
  2.   console.log('Value changed from', prev, 'to', current);) U* b1 A/ m  k: i. a: |" V
  3. }
    " j- X3 z8 [- c  R

  4. 3 L6 o$ S4 O2 C0 S  u2 q
  5. isVisible.sub(listener, true);
    * f) n1 f) `" b# p1 Q
  6. // or
    % R2 `2 t1 F7 j
  7. 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 方法:

  1. function listener(current: boolean, prev: boolean) {  w% j5 I7 R" I5 Q0 J
  2.   console.log('Value changed from', prev, 'to', current);, D) |; o+ J3 e$ n- r. C
  3. }
    / M5 L* C  r' L$ \* {& V9 P6 L6 r

  4. 6 `+ T$ w$ G0 i. a7 G( F8 T
  5. isVisible.sub(listener);0 O, V7 [% o1 L4 b/ p

  6. ! }8 a$ Q1 w/ h( }1 Y  a
  7. // Remove the listener whenever needed., `" f% u9 u0 C: i
  8. isVisible.unsub(listener);
复制代码

7 O# U( ^/ F4 P9 S3 h5 \' Y& g1 Z' N
5 Q' L% a1 f; L2 l: T+ Q
unsubAll) |* t" Y1 N0 P; x8 c1 Y4 u

. Y' T4 [7 e) e- \2 W5 K  K

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

  1. isVisible.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 方法:

  1. import { signal } from '@telegram-apps/signals';  x( g# d7 c; i2 ~5 t
  2. const isVisible = signal(false);
    6 C- w3 a* e  N3 ]. a0 L
  3. isVisible.set(true); // isVisible becomes true  o: Z# A8 r" J& O6 k
  4. 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 方法强制移除所有监听者:

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

0 Z& s4 F( g" H. O& O6 O
1 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 u

computed 函数构建了一个计算 signal,当被调用signal的任何 发生变化时,该 signal 会自动重新计算。

这里有一个例子:

  1. import { signal, computed } from '@telegram-apps/signals';* _+ S1 z  R7 f- u; @
  2. ( |) u0 @. N( Z: ~9 }
  3. const a = signal(2);
    2 R) a3 u! U! M0 K$ b
  4. const b = signal(2);
    / r; ]1 I" D7 D8 A; b5 U" b
  5. const sum = computed(() => a() + b()); // 4+ v: i  d3 Q* e8 Q5 c/ S1 `8 n

  6. 4 x% N- O- d1 ]  U/ r( [0 X
  7. a.set(5); // sum becomes 7( u& t3 c* N5 v$ @% Y# |
  8. b.set(5); // sum becomes 10
复制代码

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

' |$ e4 `. _) N, _6 N3 I7 d
批量更改

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

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

  1. <blockquote><font size="3">import { signal, computed, batch } from '@telegram-apps/signals';) o" D& }3 t- z/ \; Q

  2. 1 p; n6 ]; ], j$ y2 _/ R$ f
  3. const a = signal(1);
    ' `7 b7 A4 d$ m0 q( [* o( ~
  4. const b = signal(2);0 g. n- S$ D. Z* _
  5. const c = signal(3);
    8 [3 ?6 Y' j* A5 l
  6. const sum = computed(() => a() + b() + c()); // 66 r6 `, K' J/ u8 d% _

  7. - m/ a% N: _, G" a# C# b( S
  8. // Without batching, re-computation happens 3 times:( v8 U5 Y/ Y% u0 q8 b
  9. a.set(2); // sum recomputes and becomes 7
    ! M3 t  L7 |) E) t1 E
  10. b.set(3); // sum recomputes and becomes 8
    2 s- `! _, m7 w% b( ~4 E
  11. c.set(4); // sum recomputes and becomes 96 `/ ?  v6 g" x7 |" v* |* P

  12. 0 Y1 y. n  G6 |! p* y) z/ H5 o
  13. // Reset each signal.
    : V8 Q$ T& Y% P2 H! f$ e& m- y
  14. a.reset();' y5 K. J, N' z0 `& {" |* o
  15. b.reset();7 ]: G; H0 @2 _# X! f2 Z8 X$ T
  16. c.reset();' e3 x& s3 b) g# n( C7 e
  17. // Note: reset calls the set method, which also causes
    / G/ o4 H: S8 R6 A6 L! L( M' z. {: p
  18. // the sum signal to recompute.
    ) {& ~6 o# U0 c8 U
  19. ! J3 x. B' p5 V& t6 C
  20. // Now, let's optimize using the batch function:
    0 t+ j# x0 @$ b8 t0 V5 s
  21. batch(() => {
    : E, U4 W# y, B
  22.   a.set(2);
    # |$ H1 `" I: u1 k' r
  23.   b.set(3);
    % o  u9 M# l' d/ K
  24.   c.set(4);
    + o2 V$ A  M# p3 Q; y
  25. });- T5 f% A5 O- D. J
  26. // At this point, sum will recompute only once because" ~: B3 h9 J, \) ^* x+ B0 f4 E3 Y- j' P
  27. // batch causes the sum signal to wait for the function to complete,8 X8 G2 v. y  R+ ^
  28. // and then it triggers the recomputation.
    % \( }6 Q6 P! @
  29. 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
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则