Skip to content

Commit 3954ddb

Browse files
Merge pull request #504 from preactjs/bugfix-iso-route-flashing-3
2 parents 58b9091 + c6daf81 commit 3954ddb

File tree

3 files changed

+29
-21
lines changed

3 files changed

+29
-21
lines changed

.changeset/odd-singers-explode.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"preact-iso": patch
3+
---
4+
5+
Bugfix: fix route flashing for routes that render fragments

packages/preact-iso/router.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,18 @@ export function Router(props) {
7878
const prevChildren = useRef();
7979
const pending = useRef();
8080

81-
let reverse = false;
8281
if (url !== cur.current.url) {
83-
reverse = true;
8482
pending.current = null;
8583
prev.current = cur.current;
8684
prevChildren.current = curChildren.current;
8785
// old <Committer> uses the pending promise ref to know whether to render
8886
prevChildren.current.props.pending = pending;
8987
cur.current = loc;
88+
89+
// Hi! Wondering what this horrid line is for? That's totally reasonable, it is gross.
90+
// It prevents the old route from being remounted because it got shifted in the children Array.
91+
// @ts-ignore-next
92+
if (this.__v && this.__v.__k) this.__v.__k.reverse();
9093
}
9194

9295
curChildren.current = useMemo(() => {
@@ -120,11 +123,7 @@ export function Router(props) {
120123
} else commit();
121124
}, [url]);
122125

123-
// Hi! Wondering what this horrid line is for? That's totally reasonable, it is gross.
124-
// It prevents the old route from being remounted because it got shifted in the children Array.
125-
if (reverse && this.__v && this.__v.__k) this.__v.__k.reverse();
126-
127-
return [curChildren.current, prevChildren.current];
126+
return [prevChildren.current, curChildren.current];
128127
}
129128

130129
function Committer({ pending, children }) {

packages/preact-iso/test/router.test.js

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,13 @@ describe('Router', () => {
109109
});
110110

111111
it('should wait for asynchronous routes', async () => {
112-
const A = jest.fn(groggy(() => html`<h1>A</h1>`, 10));
113-
const B = jest.fn(groggy(() => html`<h1>B</h1>`, 10));
114-
const C = jest.fn(groggy(() => html`<h1>C</h1>`, 10));
112+
const route = name => html`
113+
<h1>${name}</h1>
114+
<p>hello</p>
115+
`;
116+
const A = jest.fn(groggy(() => route('A'), 1));
117+
const B = jest.fn(groggy(() => route('B'), 1));
118+
const C = jest.fn(groggy(() => html`<h1>C</h1>`, 1));
115119
let loc;
116120
render(
117121
html`
@@ -135,28 +139,28 @@ describe('Router', () => {
135139
expect(A).toHaveBeenCalledWith({ path: '/', query: {} }, expect.anything());
136140

137141
A.mockClear();
138-
await sleep(20);
142+
await sleep(10);
139143

140-
expect(scratch).toHaveProperty('innerHTML', '<h1>A</h1>');
144+
expect(scratch).toHaveProperty('innerHTML', '<h1>A</h1><p>hello</p>');
141145
expect(A).toHaveBeenCalledWith({ path: '/', query: {} }, expect.anything());
142146

143147
A.mockClear();
144148
loc.route('/b');
145149

146-
expect(scratch).toHaveProperty('innerHTML', '<h1>A</h1>');
150+
expect(scratch).toHaveProperty('innerHTML', '<h1>A</h1><p>hello</p>');
147151
expect(A).not.toHaveBeenCalled();
148152

149153
await sleep(1);
150154

151-
expect(scratch).toHaveProperty('innerHTML', '<h1>A</h1>');
155+
expect(scratch).toHaveProperty('innerHTML', '<h1>A</h1><p>hello</p>');
152156
// We should never re-invoke <A /> while loading <B /> (that would be a remount of the old route):
153157
expect(A).not.toHaveBeenCalled();
154158
expect(B).toHaveBeenCalledWith({ path: '/b', query: {} }, expect.anything());
155159

156160
B.mockClear();
157-
await sleep(20);
161+
await sleep(10);
158162

159-
expect(scratch).toHaveProperty('innerHTML', '<h1>B</h1>');
163+
expect(scratch).toHaveProperty('innerHTML', '<h1>B</h1><p>hello</p>');
160164
expect(A).not.toHaveBeenCalled();
161165
expect(B).toHaveBeenCalledWith({ path: '/b', query: {} }, expect.anything());
162166

@@ -165,7 +169,7 @@ describe('Router', () => {
165169
loc.route('/c?1');
166170
loc.route('/c');
167171

168-
expect(scratch).toHaveProperty('innerHTML', '<h1>B</h1>');
172+
expect(scratch).toHaveProperty('innerHTML', '<h1>B</h1><p>hello</p>');
169173
expect(B).not.toHaveBeenCalled();
170174

171175
await sleep(1);
@@ -174,13 +178,13 @@ describe('Router', () => {
174178
loc.route('/c?2');
175179
loc.route('/c');
176180

177-
expect(scratch).toHaveProperty('innerHTML', '<h1>B</h1>');
181+
expect(scratch).toHaveProperty('innerHTML', '<h1>B</h1><p>hello</p>');
178182
// We should never re-invoke <A /> while loading <B /> (that would be a remount of the old route):
179183
expect(B).not.toHaveBeenCalled();
180184
expect(C).toHaveBeenCalledWith({ path: '/c', query: {} }, expect.anything());
181185

182186
C.mockClear();
183-
await sleep(20);
187+
await sleep(10);
184188

185189
expect(scratch).toHaveProperty('innerHTML', '<h1>C</h1>');
186190
expect(B).not.toHaveBeenCalled();
@@ -193,7 +197,7 @@ describe('Router', () => {
193197
loc.route('/b');
194198
await sleep(1);
195199

196-
expect(scratch).toHaveProperty('innerHTML', '<h1>B</h1>');
200+
expect(scratch).toHaveProperty('innerHTML', '<h1>B</h1><p>hello</p>');
197201
expect(C).not.toHaveBeenCalled();
198202
// expect(B).toHaveBeenCalledTimes(1);
199203
expect(B).toHaveBeenCalledWith({ path: '/b', query: {} }, expect.anything());
@@ -202,7 +206,7 @@ describe('Router', () => {
202206
loc.route('/');
203207
await sleep(1);
204208

205-
expect(scratch).toHaveProperty('innerHTML', '<h1>A</h1>');
209+
expect(scratch).toHaveProperty('innerHTML', '<h1>A</h1><p>hello</p>');
206210
expect(B).not.toHaveBeenCalled();
207211
// expect(A).toHaveBeenCalledTimes(1);
208212
expect(A).toHaveBeenCalledWith({ path: '/', query: {} }, expect.anything());

0 commit comments

Comments
 (0)