From 8c15092cecde9c6bbfd5d351a6bd1208a86834e5 Mon Sep 17 00:00:00 2001 From: jdecroock Date: Thu, 21 Nov 2024 08:34:19 +0100 Subject: [PATCH] Ensure state updates work in signals --- hooks/src/index.js | 10 +++---- hooks/test/browser/useState.test.js | 44 ++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/hooks/src/index.js b/hooks/src/index.js index e70353ba05..92a05f0a54 100644 --- a/hooks/src/index.js +++ b/hooks/src/index.js @@ -249,7 +249,7 @@ export function useReducer(reducer, initialState, init) { // We check whether we have components with a nextValue set that // have values that aren't equal to one another this pushes // us to update further down the tree - let shouldUpdate = false; + let shouldUpdate = hookState._component.props !== p; stateHooks.forEach(hookItem => { if (hookItem._nextValue) { const currentValue = hookItem._value[0]; @@ -259,11 +259,9 @@ export function useReducer(reducer, initialState, init) { } }); - return shouldUpdate || hookState._component.props !== p - ? prevScu - ? prevScu.call(this, p, s, c) - : true - : false; + return prevScu + ? prevScu.call(this, p, s, c) || shouldUpdate + : shouldUpdate; } currentComponent.shouldComponentUpdate = updateHookState; diff --git a/hooks/test/browser/useState.test.js b/hooks/test/browser/useState.test.js index 58b152afc8..ffa99e7902 100644 --- a/hooks/test/browser/useState.test.js +++ b/hooks/test/browser/useState.test.js @@ -1,5 +1,5 @@ import { setupRerender, act } from 'preact/test-utils'; -import { createElement, render, createContext } from 'preact'; +import { createElement, render, createContext, Component } from 'preact'; import { useState, useContext, useEffect } from 'preact/hooks'; import { setupScratch, teardown } from '../../../test/_util/helpers'; @@ -371,4 +371,46 @@ describe('useState', () => { rerender(); expect(scratch.innerHTML).to.equal('

hello world!!!

'); }); + + describe('Global sCU', () => { + let prevScu; + before(() => { + prevScu = Component.prototype.shouldComponentUpdate; + Component.prototype.shouldComponentUpdate = () => { + return true; + }; + }); + + after(() => { + Component.prototype.shouldComponentUpdate = prevScu; + }); + + it('correctly updates with multiple state updates', () => { + let simulateClick; + + let renders = 0; + function TestWidget() { + renders++; + const [saved, setSaved] = useState(false); + + simulateClick = () => { + setSaved(true); + setSaved(false); + }; + + return
{saved ? 'Saved!' : 'Unsaved!'}
; + } + + render(, scratch); + expect(scratch.innerHTML).to.equal('
Unsaved!
'); + expect(renders).to.equal(1); + + act(() => { + simulateClick(); + }); + + expect(scratch.innerHTML).to.equal('
Unsaved!
'); + expect(renders).to.equal(2); + }); + }); });