Skip to content

Commit f51eef4

Browse files
Fix accessing signals from Preact Class Component constructor. (#679)
Co-authored-by: Jovi De Croock <[email protected]>
1 parent b5f5450 commit f51eef4

File tree

3 files changed

+64
-16
lines changed

3 files changed

+64
-16
lines changed

.changeset/loud-impalas-swim.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@preact/signals": patch
3+
---
4+
5+
Fix accessing signals from Preact Class Component constructor.

packages/preact/src/index.ts

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { options, Component, isValidElement } from "preact";
1+
import { options, Component, isValidElement, Fragment } from "preact";
22
import { useRef, useMemo, useEffect } from "preact/hooks";
33
import {
44
signal,
@@ -190,25 +190,29 @@ hook(OptionsTypes.DIFF, (old, vnode) => {
190190

191191
/** Set up Updater before rendering a component */
192192
hook(OptionsTypes.RENDER, (old, vnode) => {
193-
setCurrentUpdater();
194-
195-
let updater;
193+
// Ignore the Fragment inserted by preact.createElement().
194+
if (vnode.type !== Fragment) {
195+
setCurrentUpdater();
196196

197-
let component = vnode.__c;
198-
if (component) {
199-
component._updateFlags &= ~HAS_PENDING_UPDATE;
197+
let updater;
200198

201-
updater = component._updater;
202-
if (updater === undefined) {
203-
component._updater = updater = createUpdater(() => {
204-
component._updateFlags |= HAS_PENDING_UPDATE;
205-
component.setState({});
206-
});
199+
let component = vnode.__c;
200+
if (component) {
201+
component._updateFlags &= ~HAS_PENDING_UPDATE;
202+
203+
updater = component._updater;
204+
if (updater === undefined) {
205+
component._updater = updater = createUpdater(() => {
206+
component._updateFlags |= HAS_PENDING_UPDATE;
207+
component.setState({});
208+
});
209+
}
207210
}
211+
212+
currentComponent = component;
213+
setCurrentUpdater(updater);
208214
}
209215

210-
currentComponent = component;
211-
setCurrentUpdater(updater);
212216
old(vnode);
213217
});
214218

packages/preact/test/index.test.tsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ import {
77
useSignal,
88
} from "@preact/signals";
99
import type { ReadonlySignal } from "@preact/signals";
10-
import { createElement, createRef, render, createContext } from "preact";
10+
import {
11+
createElement,
12+
createRef,
13+
render,
14+
createContext,
15+
Component,
16+
} from "preact";
1117
import type { ComponentChildren, FunctionComponent, VNode } from "preact";
1218
import { useContext, useEffect, useRef, useState } from "preact/hooks";
1319
import { setupRerender, act } from "preact/test-utils";
@@ -962,4 +968,37 @@ describe("@preact/signals", () => {
962968
"<div><div>4</div><div>5</div><div>6</div></div>"
963969
);
964970
});
971+
972+
describe("Preact class Component", () => {
973+
it("should support reading signal in class component constructor", async () => {
974+
const count = signal(1);
975+
const spy = sinon.spy();
976+
977+
class App extends Component<{ x: number }, unknown> {
978+
constructor(props: { x: number }) {
979+
super(props);
980+
spy("constructor:" + count.value);
981+
}
982+
983+
componentWillMount() {
984+
spy("willmount:" + count.value);
985+
}
986+
987+
render() {
988+
return <div>{count}</div>;
989+
}
990+
}
991+
expect(() =>
992+
act(() => {
993+
render(<App x={1} />, scratch);
994+
count.value = 2;
995+
rerender();
996+
})
997+
).not.to.throw();
998+
expect(scratch.innerHTML).to.equal("<div>2</div>");
999+
expect(spy).to.have.been.calledTwice;
1000+
expect(spy).to.have.been.calledWith("constructor:1");
1001+
expect(spy).to.have.been.calledWith("willmount:1");
1002+
});
1003+
});
9651004
});

0 commit comments

Comments
 (0)