diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js index afd366aaa203..65e4188dc9c4 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js @@ -564,7 +564,7 @@ describe('ReactDOMServerHooks', () => { }); describe('useCallback', () => { - itRenders('should ignore callbacks on the server', async render => { + itRenders('should not invoke the passed callbacks', async render => { function Counter(props) { useCallback(() => { yieldValue('should not be invoked'); @@ -589,6 +589,34 @@ describe('ReactDOMServerHooks', () => { expect(domNode.tagName).toEqual('SPAN'); expect(domNode.textContent).toEqual('Count: 5'); }); + + itRenders( + 'should only change the returned reference when the inputs change', + async render => { + function CapitalizedText(props) { + const [text, setText] = useState(props.text); + const [count, setCount] = useState(0); + const capitalizeText = useCallback(() => text.toUpperCase(), [text]); + yieldValue(capitalizeText); + if (count < 3) { + setCount(count + 1); + } + if (text === 'hello' && count === 2) { + setText('hello, world.'); + } + return ; + } + + const domNode = await render(); + const [first, second, third, fourth, result] = clearYields(); + expect(first).toBe(second); + expect(second).toBe(third); + expect(third).not.toBe(fourth); + expect(result).toEqual('HELLO, WORLD.'); + expect(domNode.tagName).toEqual('SPAN'); + expect(domNode.textContent).toEqual('HELLO, WORLD.'); + }, + ); }); describe('useImperativeHandle', () => { diff --git a/packages/react-dom/src/server/ReactPartialRendererHooks.js b/packages/react-dom/src/server/ReactPartialRendererHooks.js index 23e5af5b0c7d..ba69b1f37582 100644 --- a/packages/react-dom/src/server/ReactPartialRendererHooks.js +++ b/packages/react-dom/src/server/ReactPartialRendererHooks.js @@ -456,8 +456,7 @@ export function useCallback( callback: T, deps: Array | void | null, ): T { - // Callbacks are passed as they are in the server environment. - return callback; + return useMemo(() => callback, deps); } function useResponder(responder, props): ReactEventResponderListener {