Skip to content

Commit 0fc547c

Browse files
authored
Ensure state updates work in signals (#4560)
1 parent 68ada1a commit 0fc547c

File tree

2 files changed

+47
-7
lines changed

2 files changed

+47
-7
lines changed

hooks/src/index.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ export function useReducer(reducer, initialState, init) {
249249
// We check whether we have components with a nextValue set that
250250
// have values that aren't equal to one another this pushes
251251
// us to update further down the tree
252-
let shouldUpdate = false;
252+
let shouldUpdate = hookState._component.props !== p;
253253
stateHooks.forEach(hookItem => {
254254
if (hookItem._nextValue) {
255255
const currentValue = hookItem._value[0];
@@ -259,11 +259,9 @@ export function useReducer(reducer, initialState, init) {
259259
}
260260
});
261261

262-
return shouldUpdate || hookState._component.props !== p
263-
? prevScu
264-
? prevScu.call(this, p, s, c)
265-
: true
266-
: false;
262+
return prevScu
263+
? prevScu.call(this, p, s, c) || shouldUpdate
264+
: shouldUpdate;
267265
}
268266

269267
currentComponent.shouldComponentUpdate = updateHookState;

hooks/test/browser/useState.test.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { setupRerender, act } from 'preact/test-utils';
2-
import { createElement, render, createContext } from 'preact';
2+
import { createElement, render, createContext, Component } from 'preact';
33
import { useState, useContext, useEffect } from 'preact/hooks';
44
import { setupScratch, teardown } from '../../../test/_util/helpers';
55

@@ -371,4 +371,46 @@ describe('useState', () => {
371371
rerender();
372372
expect(scratch.innerHTML).to.equal('<p>hello world!!!</p>');
373373
});
374+
375+
describe('Global sCU', () => {
376+
let prevScu;
377+
before(() => {
378+
prevScu = Component.prototype.shouldComponentUpdate;
379+
Component.prototype.shouldComponentUpdate = () => {
380+
return true;
381+
};
382+
});
383+
384+
after(() => {
385+
Component.prototype.shouldComponentUpdate = prevScu;
386+
});
387+
388+
it('correctly updates with multiple state updates', () => {
389+
let simulateClick;
390+
391+
let renders = 0;
392+
function TestWidget() {
393+
renders++;
394+
const [saved, setSaved] = useState(false);
395+
396+
simulateClick = () => {
397+
setSaved(true);
398+
setSaved(false);
399+
};
400+
401+
return <div>{saved ? 'Saved!' : 'Unsaved!'}</div>;
402+
}
403+
404+
render(<TestWidget />, scratch);
405+
expect(scratch.innerHTML).to.equal('<div>Unsaved!</div>');
406+
expect(renders).to.equal(1);
407+
408+
act(() => {
409+
simulateClick();
410+
});
411+
412+
expect(scratch.innerHTML).to.equal('<div>Unsaved!</div>');
413+
expect(renders).to.equal(2);
414+
});
415+
});
374416
});

0 commit comments

Comments
 (0)