diff --git a/docs/usePreviousDistinct.md b/docs/usePreviousDistinct.md
new file mode 100644
index 0000000000..484110aa25
--- /dev/null
+++ b/docs/usePreviousDistinct.md
@@ -0,0 +1,51 @@
+# `usePreviousDistinct`
+
+Just like `usePrevious` but it will only update once the value actually changes. This is important when other
+hooks are involved and you aren't just interested in the previous props version, but want to know the previous
+distinct value
+
+## Usage
+
+```jsx
+import {usePreviousDistinct, useCounter} from 'react-use';
+
+const Demo = () => {
+ const [count, { inc: relatedInc }] = useCounter(0);
+ const [unrelatedCount, { inc }] = useCounter(0);
+ const prevCount = usePreviousDistinct(count);
+
+ return (
+
+ Now: {count}, before: {prevCount}
+ relatedInc()}>Increment
+ Unrelated: {unrelatedCount}
+ inc()}>Increment Unrelated
+
+ );
+};
+```
+
+You can also provide a way of identifying the value as unique. By default, a strict equals is used.
+
+```jsx
+import {usePreviousDistinct} from 'react-use';
+
+const Demo = () => {
+ const [str, setStr] = React.useState("something_lowercase");
+ const [unrelatedCount] = React.useState(0);
+ const prevStr = usePreviousDistinct(str, (prev, next) => (prev && prev.toUpperCase()) === next.toUpperCase());
+
+ return (
+
+ Now: {count}, before: {prevCount}
+ Unrelated: {unrelatedCount}
+
+ );
+};
+```
+
+## Reference
+
+```ts
+const prevState = usePreviousDistinct = (state: T, compare?: (prev: T | undefined, next: T) => boolean): T;
+```
diff --git a/src/__stories__/usePreviousDistinct.story.tsx b/src/__stories__/usePreviousDistinct.story.tsx
new file mode 100644
index 0000000000..fa9bebefe7
--- /dev/null
+++ b/src/__stories__/usePreviousDistinct.story.tsx
@@ -0,0 +1,23 @@
+import { storiesOf } from '@storybook/react';
+import * as React from 'react';
+import { usePreviousDistinct, useCounter } from '..';
+import ShowDocs from './util/ShowDocs';
+
+const Demo = () => {
+ const [count, { inc: relatedInc }] = useCounter(0);
+ const [unrelatedCount, { inc }] = useCounter(0);
+ const prevCount = usePreviousDistinct(count);
+
+ return (
+
+ Now: {count}, before: {prevCount}
+ relatedInc()}>Increment
+ Unrelated: {unrelatedCount}
+ inc()}>Increment Unrelated
+
+ );
+};
+
+storiesOf('State|usePreviousDistinct', module)
+ .add('Docs', () => )
+ .add('Demo', () => );
diff --git a/src/__tests__/usePreviousDistinct.test.tsx b/src/__tests__/usePreviousDistinct.test.tsx
new file mode 100644
index 0000000000..073c86b11c
--- /dev/null
+++ b/src/__tests__/usePreviousDistinct.test.tsx
@@ -0,0 +1,65 @@
+import { renderHook } from '@testing-library/react-hooks';
+import usePreviousDistinct from '../usePreviousDistinct';
+
+describe('usePreviousDistinct with default compare', () => {
+ const hook = renderHook(props => usePreviousDistinct(props), { initialProps: 0 });
+
+ it('should return undefined on initial render', () => {
+ expect(hook.result.current).toBe(undefined);
+ });
+
+ it('should return previous state only after a different value is rendered', () => {
+ expect(hook.result.current).toBeUndefined();
+ hook.rerender(1);
+ expect(hook.result.current).toBe(0);
+ hook.rerender(2);
+ hook.rerender(2);
+ expect(hook.result.current).toBe(1);
+
+ hook.rerender(3);
+ expect(hook.result.current).toBe(2);
+ });
+});
+
+describe('usePreviousDistinct with complex comparison', () => {
+ const exampleObjects = [
+ {
+ id: 'something-unique',
+ name: 'Nancy',
+ },
+ {
+ id: 'something-unique2',
+ name: 'Fred',
+ },
+ {
+ id: 'something-unique3',
+ name: 'Bill',
+ },
+ {
+ id: 'something-unique4',
+ name: 'Alice',
+ },
+ ];
+ const hook = renderHook(
+ props => usePreviousDistinct(props, (prev, next) => (prev && prev.id) === (next && next.id)),
+ {
+ initialProps: exampleObjects[0],
+ }
+ );
+
+ it('should return undefined on initial render', () => {
+ expect(hook.result.current).toBe(undefined);
+ });
+
+ it('should return previous state only after a different value is rendered', () => {
+ expect(hook.result.current).toBeUndefined();
+ hook.rerender(exampleObjects[1]);
+ expect(hook.result.current).toMatchObject(exampleObjects[0]);
+ hook.rerender(exampleObjects[2]);
+ hook.rerender(exampleObjects[2]);
+ expect(hook.result.current).toMatchObject(exampleObjects[1]);
+
+ hook.rerender(exampleObjects[3]);
+ expect(hook.result.current).toMatchObject(exampleObjects[2]);
+ });
+});
diff --git a/src/index.ts b/src/index.ts
index 5a83944fc6..9fc6319435 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -55,6 +55,7 @@ export { default as useOrientation } from './useOrientation';
export { default as usePageLeave } from './usePageLeave';
export { default as usePermission } from './usePermission';
export { default as usePrevious } from './usePrevious';
+export { default as usePreviousDistinct } from './usePreviousDistinct';
export { default as usePromise } from './usePromise';
export { default as useRaf } from './useRaf';
export { default as useRafLoop } from './useRafLoop';
diff --git a/src/usePreviousDistinct.ts b/src/usePreviousDistinct.ts
new file mode 100644
index 0000000000..c78b00bcd2
--- /dev/null
+++ b/src/usePreviousDistinct.ts
@@ -0,0 +1,19 @@
+import { useRef } from 'react';
+
+function strictEquals(prev: T | undefined, next: T) {
+ return prev === next;
+}
+
+export default function usePreviousDistinct(
+ value: T,
+ compare: (prev: T | undefined, next: T) => boolean = strictEquals
+) {
+ const prevRef = useRef();
+ const curRef = useRef();
+ if (!compare(curRef.current, value)) {
+ prevRef.current = curRef.current;
+ curRef.current = value;
+ }
+
+ return prevRef.current;
+}