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

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

回答

收藏

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

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

本帖最后由 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
  1. pnpm i @telegram-apps/signals
复制代码
npm 9 C# P' G% d/ K
  1. npm i @telegram-apps/signals
复制代码
yarn % Z1 A7 G4 s6 s
  1. yarn add @telegram-apps/signals
    $ {" \" n( O1 K, d: m
复制代码
& w" M5 @* ^; [$ C( D
Signal

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

  1. import { signal } from '@telegram-apps/signals';
    # K/ M! _+ P, N6 G! ]; {" ^

  2. & j# u- k6 g4 u' J- \( }$ U
  3. const isVisible = signal(false);
    9 b* F% }& E0 N
  4. : S1 \; l" ?8 N4 M- A3 T( d
复制代码

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

  1. console.log('The element is', isVisible() ? 'visible' : 'invisible');+ ?' h5 N* \" N' D: \
复制代码

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


# \( q  _  E/ C" b5 h" s/ C, v3 H
  1. const s = signal(10, {, O. K; r  s+ U, R+ C/ A8 D8 H% \
  2.   equals(current, next) {
    / y# u) Z) N1 {* X: |
  3.     // Will not update the signal if the next value is% ]) D- d$ |6 a: v9 {( Y% E
  4.     // higher than the current one.- u* D8 b% e9 j) a+ h) }/ U
  5.     return next > current;* n! l7 f, A: B+ F$ g6 I% M
  6.   }3 n5 z: w) Y2 t5 e
  7. });
    ( b3 i) X7 \+ n' \( F: @1 A
  8. s.set(20); // will not update the signal: Y8 X- f: T9 H* }
  9. s.set(5); // will update the signal
复制代码
$ y% g/ C( u5 w* m' A
set8 J! F0 p: K( \4 P

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

  1. isVisible.set(true);
复制代码
3 Q( @! i* U; u$ u, b, U! h; u' r8 k
sub6 n/ d' g9 k5 x: X+ [

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

  1. const removeListener = isVisible.sub((current, prev) => {7 ]5 U2 `& L) t" F% c& Y0 \
  2.   console.log('Value changed from', prev, 'to', current);) s+ i; c$ \2 ~
  3. });. ]4 r+ h9 `6 ^) D' I, l

  4. 9 T, q; E0 S: s6 K3 L- b  a  N
  5. // Remove the listener whenever needed.6 b6 O& x% v2 `) Y
  6. removeListener();
复制代码

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

6 m8 \5 B6 ~# F* v4 x; P, b& Z7 y' E
  1. function listener(current: boolean, prev: boolean) {: l9 T2 b5 O3 R0 \9 a, Y+ K6 z
  2.   console.log('Value changed from', prev, 'to', current);% `+ x0 N! y& N  q2 M
  3. }. W5 {9 \, G+ p, O; J
  4. ) f" \& H; I) `0 P
  5. isVisible.sub(listener, true);
    ( H0 n) O4 h; X2 e) [1 I
  6. // or* P( Z, \6 K( k* d3 L( G
  7. isVisible.sub(listener, { once: true });
复制代码

" `7 K6 S6 y; Z4 W" a2 p# U# [
) k4 l5 b9 z3 t
unsub
6 ~) K! |4 B% O
- Q: \# c, ^1 u3 e; r' Y

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

  1. function listener(current: boolean, prev: boolean) {; f9 w, F! s. O# i
  2.   console.log('Value changed from', prev, 'to', current);. C; j! K# v4 k" S: {
  3. }2 V# [9 X9 g" O  Y
  4.   k$ C( [! M$ q$ B$ h1 Y
  5. isVisible.sub(listener);
    & ^* F' v' w; X1 r. j! N+ k5 j, w
  6. ; d3 @3 J6 m9 v
  7. // Remove the listener whenever needed.$ K5 C' I2 K& ~# B0 t% l
  8. 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 方法:

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

  1. import { signal } from '@telegram-apps/signals';
    # n) e# ^* |4 K4 N& J
  2. const isVisible = signal(false);$ |( q9 V# D8 o; o
  3. isVisible.set(true); // isVisible becomes true% w; c. K2 y0 c& a& n8 `
  4. isVisible.reset(); // isVisible becomes false again
复制代码
3 |- d: P& Y7 t6 i

4 y2 k3 U1 j9 h" D
destroy+ ]+ L  g5 O# @. Y) V+ U9 l

; R$ i. Y1 k7 A, T9 s1 G

当不再需要该信号且该信号没有被任何计算信号监听时,开发者 可以使用 destroy 方法强制移除所有监听者:

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

这里有一个例子:

  1. import { signal, computed } from '@telegram-apps/signals';
    2 ?! k* W  H4 [" o; z# t- R/ e
  2. % s, K& g& o  o
  3. const a = signal(2);* G5 b, J2 _& o9 K
  4. const b = signal(2);
    $ ?& p, {1 M; Q5 s8 \+ B
  5. const sum = computed(() => a() + b()); // 42 b$ n" D( B+ K* }' q0 G% k  I
  6. / A! }4 Q. @& i7 U
  7. a.set(5); // sum becomes 7: r' Z0 c$ S" d: ^% A
  8. b.set(5); // sum becomes 10
复制代码

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


1 ]4 X7 n; j# H- v0 q
批量更改

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

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

  1. <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

  2. ; f# V) Z1 ]/ u8 l4 F* x5 N; ~0 I9 }! f
  3. const a = signal(1);
    5 I  B/ c& i- ]# h& {
  4. const b = signal(2);
    ; D$ C! A* I( }6 v$ B9 i6 I
  5. const c = signal(3);
    ! @* P3 f+ N+ I
  6. const sum = computed(() => a() + b() + c()); // 6
    3 T% ?# U3 U  B7 Q
  7. 2 K4 e: j' K% y6 S0 n
  8. // Without batching, re-computation happens 3 times:
    ! J! w8 p! N3 V& l) C3 r' e& l
  9. a.set(2); // sum recomputes and becomes 7
    # V0 n0 k; f0 y. r; n6 K, T# o1 g
  10. b.set(3); // sum recomputes and becomes 8  R7 \8 S+ }) k0 ?# h  s9 L
  11. c.set(4); // sum recomputes and becomes 9) Z5 }: ^$ E8 J. O; J4 F) @
  12. 7 b+ O1 D3 z. D3 }6 v% o
  13. // Reset each signal.
    5 t+ H. P2 A' X5 f1 ~/ M6 ~
  14. a.reset();/ S, {% S! v8 A: l! f4 W
  15. b.reset();. {$ B0 G, ]" n; ^2 L- c+ @
  16. c.reset();) M- s2 i0 G1 z. D
  17. // Note: reset calls the set method, which also causes
    - [) \5 W$ G  ~  p
  18. // the sum signal to recompute.
    / n5 P0 J' t( \

  19. / r- P( a, k) \% C4 u. b
  20. // Now, let's optimize using the batch function:
    $ f; x) n2 d. U
  21. batch(() => {" `$ i# U8 w3 ?; S' E
  22.   a.set(2);
    ! t8 e" [) X0 |+ n7 i
  23.   b.set(3);+ ?; O0 ^- T7 K
  24.   c.set(4);& K! g9 p! j& C5 H# @# T
  25. });4 \) K8 ]! I# D
  26. // At this point, sum will recompute only once because9 N5 e5 I$ l* N; }7 [0 u( a
  27. // batch causes the sum signal to wait for the function to complete,
    8 I) Q+ p* v7 `# Q% w
  28. // and then it triggers the recomputation.
    4 s& K" L, T( S3 S! y
  29. 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
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则