本帖最后由 riyad 于 2025-2-22 20:09 编辑
7 p2 U6 N+ H9 y' s3 E3 p! e
. ]2 U2 J+ h8 O1 u5 O我们在整个 @telegram-apps 软件包中使用的 signals 实现。 ' w- l+ q d5 y6 g
安装pnpm 7 A7 n/ M% h- ~3 y9 y
- pnpm i @telegram-apps/signals
复制代码 npm
' ^, f/ Z' Z" k/ _- T$ R- npm i @telegram-apps/signals
复制代码 yarn ' {) X0 b% z* u+ N$ ^
- yarn add @telegram-apps/signals6 ]4 e0 u* m9 H# j( k' h
复制代码
' j1 o" q" w( T. Z& ySignalsignal 函数是最简单的 signal 构造函数,被其他软件包函数所使用。 要 创建新 signal,只需传递初始值即可: - import { signal } from '@telegram-apps/signals';
1 L, r; Z) J! u' [
7 \; ^. |( I/ s" @- const isVisible = signal(false);
% S! x9 R( H( T
; f: Q" ~; i, E% v4 d# d# G# M1 d7 A
复制代码返回值代表一个具有实用方法的函数。 函数本身返回 当前信号值。 - console.log('The element is', isVisible() ? 'visible' : 'invisible');6 {2 \1 C- O# o9 H# E7 q8 ~" J
复制代码该函数还接受选项作为第二个参数。 开发人员可以指定 equals 函数,该函数接受当前值和输入值,如果认为它们相等,则返回 true, 。
* O& i6 K, g1 H- const s = signal(10, {; q/ q8 ]3 x/ a- |; S
- equals(current, next) {
- G0 L$ u! s( C/ X3 x - // Will not update the signal if the next value is) a/ k6 E9 y" C% b7 o: S
- // higher than the current one.. A, e2 |3 \" b) `9 a: N* \0 E
- return next > current;- ~) A; o* v; H
- }6 ]- [# t. c6 d/ }2 w
- });
# g/ C* g4 D, T" c: ]- ]1 K T6 ~ - s.set(20); // will not update the signal3 C8 y* x1 U* p+ z' b
- s.set(5); // will update the signal
复制代码 3 V. u! R5 P3 |) o
set1 A- W3 \7 k2 t
要设置新值,请使用 set 方法: 9 |/ W- S$ K- n, [ V
sub) Q3 h3 T" l I( F
要跟踪信号变化,请使用 sub 方法。 它返回一个函数,用于移除绑定的 监听器。 监听器接受两个参数:当前值和上一个值。 - const removeListener = isVisible.sub((current, prev) => {
5 c0 Q& j2 x& w/ H, f# P - console.log('Value changed from', prev, 'to', current);: I9 n8 }8 _4 V# a
- });4 b _' s5 n" i
8 O: a& y8 j' P+ \0 j; N- // Remove the listener whenever needed.! f& y2 k5 E; h( u. _
- removeListener();
复制代码要只调用监听器一次,请使用第二个: & e; u' i$ h3 v% L6 d- {7 r d1 k e
- function listener(current: boolean, prev: boolean) {8 m/ t2 H5 r6 i! U6 f4 [
- console.log('Value changed from', prev, 'to', current);
' c& j) D- o0 Y% b, F - }
+ @* W4 }9 _- e) M3 ?* B
0 W& ~- e+ ]% h, d) }" _ ^- isVisible.sub(listener, true);
8 W9 r: u. x! f/ A" v. K - // or Y4 W1 J; Q+ s, `8 |$ J6 E3 i
- isVisible.sub(listener, { once: true });
复制代码 $ O0 r* F# x/ ?) h; ^
# T! [; ~0 j/ M* t) J! ?- C
unsub
8 r$ ]7 U" o3 v4 G$ n- p) B
+ y% h9 ?& q2 P; c4 H+ m另外,要移除监听器,开发人员可以使用 unsub 方法: - function listener(current: boolean, prev: boolean) {
$ ]; {3 b4 D& u6 Q9 R - console.log('Value changed from', prev, 'to', current);
/ X6 I( \: f" o( K: O - }$ J2 y0 H% ]9 z* t1 \+ y d5 L
3 D7 A) K# E& I5 l, Q) M, h- isVisible.sub(listener);7 n2 j Q5 p' W8 v1 l# F
+ @3 w& _2 n. [ K8 o, u( A- // Remove the listener whenever needed.
; g* y: k4 p h - isVisible.unsub(listener);
复制代码
8 l$ G2 L, O; M! {" }$ L# N$ l8 m: {
unsubAll
7 D" X$ ^1 h$ F
$ }+ R7 _& G7 ~% r6 a要移除所有监听器,请使用 unsubAll 方法: INFO 此方法不会移除计算信号添加的监听器。 $ H. K" A: h8 l$ W# v2 V; e0 r6 v
. y( v! }- o2 J+ h, t# |
reset& a& g5 t4 G$ W9 N: e$ C1 M& T
9 X1 ~$ [0 w) l( r, J要恢复到最初指定的值,请使用 reset 方法: - import { signal } from '@telegram-apps/signals';3 g# l* _. S0 B
- const isVisible = signal(false);2 V2 P5 Y; L6 U G
- isVisible.set(true); // isVisible becomes true
5 { [; z/ A# M8 S2 v - isVisible.reset(); // isVisible becomes false again
复制代码 O0 Y$ E; G# r- H5 }
0 ~% h1 d, _: U/ f$ F
destroy/ g2 f! c. y9 ^- Q$ D( r
7 _0 } I: h1 ?3 e% l% l( r当不再需要该信号且该信号没有被任何计算信号监听时,开发者 可以使用 destroy 方法强制移除所有监听者:
% \1 `7 ^; I. p0 {. c5 w% E. n. ]! A: R1 C, L5 t1 |
: E9 L$ t0 O9 t* X" QComputed
8 x/ @4 k% w2 r. Q
$ x6 E& c1 Z/ \5 E# f) Wcomputed 函数构建了一个计算 signal,当被调用signal的任何 发生变化时,该 signal 会自动重新计算。 这里有一个例子: - import { signal, computed } from '@telegram-apps/signals';1 D* K: w1 h2 p# p5 p$ m' i. B
9 U- N! z4 e. E5 g# ~/ [- const a = signal(2);
8 o, c2 E0 y* D% y! d) P - const b = signal(2);5 \4 n7 P% @( i
- const sum = computed(() => a() + b()); // 4; W& u& n3 L! v0 P5 E* M j
- ( n) I" b; P% J2 M0 H* o9 G
- a.set(5); // sum becomes 7! q- Y( c' |3 A, g
- b.set(5); // sum becomes 10
复制代码返回值代表一个缺少 set 和 reset 方法的信号。 " K6 r; E! U( T: h
批量更改batch 函数创建一个作用域,在此对 signal 突变进行批处理。 当开发人员希望防止计算 signal 在几个 相关 signal 连续变化时重新计算时,该功能非常有用。 - <blockquote><font size="3">import { signal, computed, batch } from '@telegram-apps/signals';1 G i) w1 N0 s) Q
8 L( f/ n/ p! ?& L, F- const a = signal(1);
U, j& y% `/ b2 V9 ], ? - const b = signal(2);, {- h! U; J; h$ m7 h' C
- const c = signal(3);
7 g I* Z) _+ I) m4 I) ? - const sum = computed(() => a() + b() + c()); // 6- \/ X/ b7 i9 I. M+ K5 ~4 j
9 g- M) A! ^1 e/ R2 i- // Without batching, re-computation happens 3 times:( H7 f" I( i3 s9 k1 F
- a.set(2); // sum recomputes and becomes 7& `# M! d: L6 c4 P5 w
- b.set(3); // sum recomputes and becomes 8* i" g, n* Q$ Y, Q1 L, L: N& E
- c.set(4); // sum recomputes and becomes 9
% s. P2 U5 _ N3 C) r5 t
* v% ^5 n& B% W3 T. x- f4 \/ ~- // Reset each signal.' g. O5 l8 N6 M: W) K- O) T& b
- a.reset();
# T6 U+ C, K" q - b.reset();5 v0 I2 K$ l) V$ c" A8 ~! ~$ M
- c.reset();
9 r5 ]. T# I/ ~$ Y) W) F2 H - // Note: reset calls the set method, which also causes
( M& _( \4 C$ T: X* q2 W - // the sum signal to recompute.4 M4 _* c0 _* X$ w
- ! }4 S% `, k; c/ ? @
- // Now, let's optimize using the batch function:
1 Y. C; P/ O9 q1 q0 O - batch(() => {( [/ y6 V+ p& b: c3 `* s5 s: y* H5 G
- a.set(2);4 b/ Y/ ~ h# O7 t1 P; B
- b.set(3);! A9 C. ]6 {7 o3 ?- O- d4 [5 t; e
- c.set(4);; ]( U M$ z, _
- });
; T& A' ]# V. c: C5 u - // At this point, sum will recompute only once because
5 ? t% i" s) P+ a9 O F - // batch causes the sum signal to wait for the function to complete,
8 T c, N% k6 _( f- @7 G/ e - // and then it triggers the recomputation.
! X! c) a: d5 m9 |& K - console.log(sum()); // 9</font>
复制代码
7 P) k" G7 J7 f. q; q5 Q7 C $ |6 I1 r; [( S" u2 y8 v1 T
) r' d: S- h) X% k
: ^: n9 i, b$ s% P/ {3 ~$ o: v
" g* Q2 z. S1 n P% M0 T
C1 H. D3 Y3 ^/ q! `0 F6 t |