diff --git a/packages/fuselage-hooks/src/index.ts b/packages/fuselage-hooks/src/index.ts index 992113424e..f55877d1fb 100644 --- a/packages/fuselage-hooks/src/index.ts +++ b/packages/fuselage-hooks/src/index.ts @@ -16,6 +16,7 @@ export * from './usePosition'; export * from './usePrefersColorScheme'; export * from './usePrefersReducedData'; export * from './usePrefersReducedMotion'; +export * from './usePrevious'; export * from './useResizeObserver'; export * from './useSafely'; export * from './useStableArray'; diff --git a/packages/fuselage-hooks/src/usePrevious.spec.ts b/packages/fuselage-hooks/src/usePrevious.spec.ts new file mode 100644 index 0000000000..995a2702e8 --- /dev/null +++ b/packages/fuselage-hooks/src/usePrevious.spec.ts @@ -0,0 +1,43 @@ +import { FunctionComponent, createElement, StrictMode, useState } from 'react'; +import { render } from 'react-dom'; +import { act } from 'react-dom/test-utils'; + +import { usePrevious } from '.'; + +it('returns previous values', () => { + let previous: number | undefined; + let current: number; + let increment: () => void; + + const TestComponent: FunctionComponent = () => { + const [count, setCount] = useState(0); + previous = usePrevious(count); + + current = count; + increment = () => { + setCount((count) => count + 1); + }; + + return null; + }; + + act(() => { + render( + createElement(StrictMode, {}, createElement(TestComponent)), + document.createElement('div') + ); + }); + + expect(current).toBe(0); + expect(previous).toBe(undefined); + + act(increment); + + expect(current).toBe(1); + expect(previous).toBe(0); + + act(increment); + + expect(current).toBe(2); + expect(previous).toBe(1); +}); diff --git a/packages/fuselage-hooks/src/usePrevious.ts b/packages/fuselage-hooks/src/usePrevious.ts new file mode 100644 index 0000000000..38a60643f5 --- /dev/null +++ b/packages/fuselage-hooks/src/usePrevious.ts @@ -0,0 +1,11 @@ +import { useEffect, useRef } from 'react'; + +export const usePrevious = (value: T): T | undefined => { + const ref = useRef(); + + useEffect(() => { + ref.current = value; + }); + + return ref.current; +};