diff --git a/packages/react-reconciler/src/ReactFiberHooks.new.js b/packages/react-reconciler/src/ReactFiberHooks.new.js index e2d5244746347..7b7d0f648ae2b 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.new.js +++ b/packages/react-reconciler/src/ReactFiberHooks.new.js @@ -1012,7 +1012,8 @@ function useMutableSource( const latestSetSnapshot = refs.setSnapshot; try { - latestSetSnapshot(latestGetSnapshot(source._source)); + const value = latestGetSnapshot(source._source); + latestSetSnapshot(() => value); // Record a pending mutable source update with the same expiration time. const suspenseConfig = requestCurrentSuspenseConfig(); diff --git a/packages/react-reconciler/src/ReactFiberHooks.old.js b/packages/react-reconciler/src/ReactFiberHooks.old.js index fc925dbe7bda2..bd44f670e60b8 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.old.js +++ b/packages/react-reconciler/src/ReactFiberHooks.old.js @@ -1004,7 +1004,8 @@ function useMutableSource( const latestSetSnapshot = refs.setSnapshot; try { - latestSetSnapshot(latestGetSnapshot(source._source)); + const value = latestGetSnapshot(source._source); + latestSetSnapshot(() => value); // Record a pending mutable source update with the same expiration time. const currentTime = requestCurrentTimeForUpdate(); diff --git a/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js b/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js index 7bdb1b44207a5..fa767df99a04c 100644 --- a/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js +++ b/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js @@ -1493,6 +1493,45 @@ describe('useMutableSource', () => { }, ); + // @gate experimental + it( + 'can store functions in source', + async () => { + const source = createSource(() => 'a'); + const mutableSource = createMutableSource(source); + + const getSnapshot = () => source.value; + + function Read() { + const fn = useMutableSource( + mutableSource, + getSnapshot, + defaultSubscribe, + ); + const value = fn(); + Scheduler.unstable_yieldValue(value); + return value; + } + + const root = ReactNoop.createRoot(); + await act(async () => { + root.render( + <> + + , + ); + }); + expect(Scheduler).toHaveYielded(['a']); + expect(root).toMatchRenderedOutput('a'); + + await act(async () => { + source.value = () => 'b'; + expect(Scheduler).toFlushUntilNextPaint(['b']); + expect(root).toMatchRenderedOutput('b'); + }); + }, + ); + // @gate experimental it('getSnapshot changes and then source is mutated during interleaved event', async () => { const {useEffect} = React;