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

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

回答

收藏

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

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

本帖最后由 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
  1. pnpm i @telegram-apps/signals
复制代码
npm
# C% ~$ ]2 F, I8 j9 V6 }1 V" |+ X
  1. npm i @telegram-apps/signals
复制代码
yarn
( r7 s1 `  B0 y8 R" X2 @" g& V1 r
  1. yarn add @telegram-apps/signals  v" {. ]. O9 }  Q
复制代码

8 n1 L) D9 r' H
Signal

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

  1. import { signal } from '@telegram-apps/signals';
    0 a0 p  S* T% s

  2. ( ~; M6 J& S) j+ C+ q. g# ]
  3. const isVisible = signal(false);, p7 Z( ]# I, R# e) X% \/ T

  4. 7 a0 A! p7 E8 ^$ |
复制代码

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

  1. 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
  1. const s = signal(10, {) W8 Z9 ^: @0 y# B
  2.   equals(current, next) {! n8 m2 {# A0 b4 K8 \) N
  3.     // Will not update the signal if the next value is
    ! z8 R9 e: E1 Y! V. Z' R" B
  4.     // higher than the current one.
    0 ?7 {0 K; k4 h
  5.     return next > current;( N1 R( f2 w7 r0 _$ h
  6.   }
    3 J  s" h0 D  `8 d
  7. });
    , ^( m5 i4 w8 w$ C* Y
  8. s.set(20); // will not update the signal
    - `2 K  v6 B% l' \8 O% H
  9. 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. isVisible.set(true);
复制代码

1 J4 R* f5 _# |, I7 d1 E5 N+ P
sub
) k- V% g3 P; }

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

  1. const removeListener = isVisible.sub((current, prev) => {
    * }$ a& ?8 M, c3 @
  2.   console.log('Value changed from', prev, 'to', current);. d" N2 A- ^% D+ B0 O, a; p
  3. });9 r9 D! j6 n# L, Q7 o: r% [6 M

  4. * P- u5 v; _* W8 d& B$ m: U+ U
  5. // Remove the listener whenever needed.
    ; N( o$ |4 h4 |3 V/ o
  6. removeListener();
复制代码

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


1 P! D+ Q" S' ~9 }
  1. function listener(current: boolean, prev: boolean) {
    ! M) {$ e- m, h  Y1 B! Y5 [7 |
  2.   console.log('Value changed from', prev, 'to', current);
    ; T% b0 q2 d4 f! v2 F8 B
  3. }4 i" i( ?/ S( ]2 V8 I' s

  4. & P: y+ t; t& u5 O: G
  5. isVisible.sub(listener, true);
    2 Z) v7 `- y& V0 y6 A
  6. // or& F- i4 t# y6 l9 c; C6 x
  7. 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 方法:

  1. function listener(current: boolean, prev: boolean) {
      }( y4 X5 a' o  \+ }, a) n
  2.   console.log('Value changed from', prev, 'to', current);
    * b+ @$ r- B& c/ W5 q
  3. }
    " \4 G9 G# h& ]
  4. # i# @3 G# q% Y; y$ ]6 J  }$ S) a
  5. isVisible.sub(listener);- R# V3 B! z* D$ V3 w" F
  6. ' p) d7 @+ P# y
  7. // Remove the listener whenever needed.# |. S/ u' w8 {9 w1 _" L
  8. 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 方法:

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

  1. import { signal } from '@telegram-apps/signals';: z# ]  |9 u, P& ^& r4 @: X
  2. const isVisible = signal(false);4 I1 H  p) w' X& d6 H, M
  3. isVisible.set(true); // isVisible becomes true
    ) C+ Q  u  z/ |
  4. 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 方法强制移除所有监听者:

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

5 d. d- |8 d9 ~( F; p* q( \
6 ]! k) o5 |9 Y1 t+ @2 h1 E: d, D

3 \, ^+ }) Z/ f; T1 x
Computed( `/ |' g1 C  a6 P/ p! A

* a* u* r. S% U

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

这里有一个例子:

  1. import { signal, computed } from '@telegram-apps/signals';
    : {$ U" {) H' x
  2. 1 w  g) w+ G/ f$ E0 n9 b
  3. const a = signal(2);
    - @7 K9 |# {: @$ c. B1 p& s/ J9 C
  4. const b = signal(2);
    6 K5 f! |: U: \* l7 V. p
  5. const sum = computed(() => a() + b()); // 4* U* a9 d1 o( M% o% j

  6. & _, R! Z# Z  ^
  7. a.set(5); // sum becomes 7
    8 [+ N8 o$ J2 C
  8. b.set(5); // sum becomes 10
复制代码

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

& ~1 a8 Y0 E7 R1 f) E8 D. u
批量更改

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

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

  1. <blockquote><font size="3">import { signal, computed, batch } from '@telegram-apps/signals';
    " B8 T6 q) G. c; c1 g4 c* b: j! f
  2. * D, B" l% j9 y; @+ Y
  3. const a = signal(1);
    ; X# D2 B0 H9 M* s5 G& ^2 H
  4. const b = signal(2);
    $ }6 ?$ U5 y5 `8 v9 c, V2 U
  5. const c = signal(3);" c$ `& `- `8 X
  6. const sum = computed(() => a() + b() + c()); // 65 ~& t. }7 s% W0 t) |7 y

  7. " W1 ~$ o( {/ c7 W3 X& ]
  8. // Without batching, re-computation happens 3 times:9 k7 s9 d% K' r' C4 x/ h7 @
  9. a.set(2); // sum recomputes and becomes 7
    ) I2 L" z* n9 v' L  z
  10. b.set(3); // sum recomputes and becomes 8% k1 Z* M7 Y- b! X5 g# w) N
  11. c.set(4); // sum recomputes and becomes 96 C4 }- u. D2 x: c
  12. 0 y* ~# M- U0 c- R  T7 l
  13. // Reset each signal.
    ) T1 ?7 k; ?& H
  14. a.reset();% C" K* Q# M9 J' l& }2 v2 |
  15. b.reset();
    7 k7 Q& {9 n8 p, j
  16. c.reset();$ A8 x. c- R) y- a4 [  @
  17. // Note: reset calls the set method, which also causes
    0 X, G% I9 i4 o. ~% i
  18. // the sum signal to recompute.
    ' f0 y0 r, Q9 \: A3 G

  19. & q) }6 M% N! L
  20. // Now, let's optimize using the batch function:( @, {) W0 E  S5 k" }4 g/ R9 U/ o
  21. batch(() => {! U. ?5 H3 V" z6 r9 X3 L
  22.   a.set(2);& }' L1 z( y4 J; u1 _
  23.   b.set(3);, H0 L3 V( K! ^% i, k, v
  24.   c.set(4);
    ! d  G, T% W5 W; E% z0 D  ~* o! Q; c
  25. });6 U2 F( C5 W  p0 l1 D1 Y' `
  26. // At this point, sum will recompute only once because
    # u/ v: N( E& F' K
  27. // batch causes the sum signal to wait for the function to complete,
    ) z3 x- n+ H& y7 R# ]* O
  28. // and then it triggers the recomputation.+ @' L0 N2 F2 |4 J
  29. 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
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则