Skip to content

Commit 856ca2b

Browse files
fix: make prefresh hmr integration easier
The callback to `useMemo` is assumed to be pure during HMR and will be re-triggered. This in turn broke the `useSignal` hooks HMR as they used side-effectful callbacks.
1 parent 6cc7005 commit 856ca2b

1 file changed

Lines changed: 18 additions & 8 deletions

File tree

packages/preact/src/index.ts

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { options, Component, isValidElement, Fragment } from "preact";
2-
import { useRef, useMemo, useEffect } from "preact/hooks";
2+
import { useRef, useEffect } from "preact/hooks";
33
import {
44
signal,
55
computed,
@@ -92,7 +92,7 @@ function SignalValue(this: AugmentedComponent, { data }: { data: Signal }) {
9292
const currentSignal = useSignal(data);
9393
currentSignal.value = data;
9494

95-
const [isText, s] = useMemo(() => {
95+
const cb = () => {
9696
let self = this;
9797
// mark the parent component as having computeds so it gets optimized
9898
let v = this.__v;
@@ -139,7 +139,12 @@ function SignalValue(this: AugmentedComponent, { data }: { data: Signal }) {
139139
};
140140

141141
return [isText, wrappedSignal];
142-
}, []);
142+
};
143+
144+
const ref = useRef<ReadonlySignal<any>[] | null>(null);
145+
if (ref.current === null) {
146+
ref.current = cb();
147+
}
143148

144149
// Rerender the component whenever `data.value` changes from a VNode
145150
// to another VNode, from text to a VNode, or from a VNode to text.
@@ -150,6 +155,7 @@ function SignalValue(this: AugmentedComponent, { data }: { data: Signal }) {
150155
//
151156
// For text-to-text updates, `.peek()` is used to skip full rerenders,
152157
// leaving them to the optimized path above.
158+
const [isText, s] = ref.current;
153159
return isText.value ? s.peek() : s.value;
154160
}
155161
SignalValue.displayName = "_st";
@@ -387,17 +393,21 @@ Component.prototype.shouldComponentUpdate = function (
387393
export function useSignal<T>(value: T, options?: SignalOptions<T>): Signal<T>;
388394
export function useSignal<T = undefined>(): Signal<T | undefined>;
389395
export function useSignal<T>(value?: T, options?: SignalOptions<T>) {
390-
return useMemo(
391-
() => signal<T | undefined>(value, options as SignalOptions),
392-
[]
393-
);
396+
const cb = () => signal<T | undefined>(value, options as SignalOptions);
397+
const ref = useRef<Signal<T | undefined> | null>(null);
398+
if (!ref.current) ref.current = cb();
399+
return ref.current;
394400
}
395401

396402
export function useComputed<T>(compute: () => T, options?: SignalOptions<T>) {
397403
const $compute = useRef(compute);
398404
$compute.current = compute;
399405
(currentComponent as AugmentedComponent)._updateFlags |= HAS_COMPUTEDS;
400-
return useMemo(() => computed<T>(() => $compute.current(), options), []);
406+
const ref = useRef<ReadonlySignal<T> | null>(null);
407+
if (!ref.current) {
408+
ref.current = computed<T>(() => $compute.current(), options);
409+
}
410+
return ref.current;
401411
}
402412

403413
function safeRaf(callback: () => void) {

0 commit comments

Comments
 (0)