Skip to content

Commit 180eab1

Browse files
committed
Delay subscribing to a component until its fully mounted
1 parent 54094d5 commit 180eab1

3 files changed

Lines changed: 387 additions & 0 deletions

File tree

.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
@@ -99,17 +99,24 @@ export interface EffectStore {
9999
getSnapshot(): number;
100100
/** startEffect - begin tracking signals used in this component */
101101
_start(): void;
102+
_subscribers: Array<{ signal: Signal; node: any }>;
103+
_sub: typeof Signal.prototype._subscribe;
102104
/** finishEffect - stop tracking the signals used in this component */
103105
f(): void;
104106
[symDispose](): void;
105107
}
106108

107109
let currentStore: EffectStore | undefined;
108110

111+
const realSubscribe = Signal.prototype._subscribe;
109112
function startComponentEffect(
110113
prevStore: EffectStore | undefined,
111114
nextStore: EffectStore
112115
) {
116+
nextStore._sub = Signal.prototype._subscribe;
117+
Signal.prototype._subscribe = function (this: Signal, node: any) {
118+
nextStore._subscribers.push({ signal: this, node });
119+
};
113120
const endEffect = nextStore.effect._start();
114121
currentStore = nextStore;
115122

@@ -121,6 +128,7 @@ function finishComponentEffect(
121128
prevStore: EffectStore | undefined,
122129
endEffect: () => void
123130
) {
131+
Signal.prototype._subscribe = this._sub;
124132
endEffect();
125133
currentStore = prevStore;
126134
}
@@ -171,6 +179,8 @@ function createEffectStore(
171179

172180
return {
173181
_usage,
182+
_subscribers: [],
183+
_sub: realSubscribe,
174184
effect: effectInstance,
175185
subscribe(onStoreChange) {
176186
onChangeNotifyReact = onStoreChange;
@@ -305,6 +315,8 @@ const noop = () => {};
305315

306316
function createEmptyEffectStore(): EffectStore {
307317
return {
318+
_subscribers: [],
319+
_sub: noop as any,
308320
_usage: UNMANAGED,
309321
effect: {
310322
_sources: undefined,
@@ -369,6 +381,13 @@ export function _useSignalsImplementation(
369381
// note: _usage is a constant here, so conditional is okay
370382
if (_usage === UNMANAGED) useIsomorphicLayoutEffect(cleanupTrailingStore);
371383

384+
useIsomorphicLayoutEffect(() => {
385+
store._subscribers.forEach(({ signal, node }) => {
386+
realSubscribe.call(signal, node);
387+
});
388+
store._subscribers = [];
389+
});
390+
372391
return store;
373392
}
374393

0 commit comments

Comments
 (0)