Skip to content

Commit 1151f46

Browse files
committed
Delay subscribing to a component until its fully mounted
1 parent a237b61 commit 1151f46

File tree

3 files changed

+387
-0
lines changed

3 files changed

+387
-0
lines changed

.changeset/nasty-rings-float.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@preact/signals-react": major
3+
---
4+
5+
Delay subscribing to signals until the component is actually mounted

packages/react/runtime/src/index.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,24 @@ export interface EffectStore {
9494
getSnapshot(): number;
9595
/** startEffect - begin tracking signals used in this component */
9696
_start(): void;
97+
_subscribers: Array<{ signal: Signal; node: any }>;
98+
_sub: typeof Signal.prototype._subscribe;
9799
/** finishEffect - stop tracking the signals used in this component */
98100
f(): void;
99101
[symDispose](): void;
100102
}
101103

102104
let currentStore: EffectStore | undefined;
103105

106+
const realSubscribe = Signal.prototype._subscribe;
104107
function startComponentEffect(
105108
prevStore: EffectStore | undefined,
106109
nextStore: EffectStore
107110
) {
111+
nextStore._sub = Signal.prototype._subscribe;
112+
Signal.prototype._subscribe = function (this: Signal, node: any) {
113+
nextStore._subscribers.push({ signal: this, node });
114+
};
108115
const endEffect = nextStore.effect._start();
109116
currentStore = nextStore;
110117

@@ -116,6 +123,7 @@ function finishComponentEffect(
116123
prevStore: EffectStore | undefined,
117124
endEffect: () => void
118125
) {
126+
Signal.prototype._subscribe = this._sub;
119127
endEffect();
120128
currentStore = prevStore;
121129
}
@@ -157,6 +165,8 @@ function createEffectStore(_usage: EffectStoreUsage): EffectStore {
157165

158166
return {
159167
_usage,
168+
_subscribers: [],
169+
_sub: realSubscribe,
160170
effect: effectInstance,
161171
subscribe(onStoreChange) {
162172
onChangeNotifyReact = onStoreChange;
@@ -291,6 +301,8 @@ const noop = () => {};
291301

292302
function createEmptyEffectStore(): EffectStore {
293303
return {
304+
_subscribers: [],
305+
_sub: noop as any,
294306
_usage: UNMANAGED,
295307
effect: {
296308
_sources: undefined,
@@ -354,6 +366,13 @@ export function _useSignalsImplementation(
354366
// note: _usage is a constant here, so conditional is okay
355367
if (_usage === UNMANAGED) useIsomorphicLayoutEffect(cleanupTrailingStore);
356368

369+
useIsomorphicLayoutEffect(() => {
370+
store._subscribers.forEach(({ signal, node }) => {
371+
realSubscribe.call(signal, node);
372+
});
373+
store._subscribers = [];
374+
});
375+
357376
return store;
358377
}
359378

0 commit comments

Comments
 (0)