Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tsx for useMemoCompare #2

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/pages/useMemoCompare.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,60 @@ function useMemoCompare(next, compare) {
return isEqual ? previous : next;
}
```

```typescript
import React, { useState, useEffect, useRef } from "react";

// Usage
function MyComponent({ obj }) {
const [state, setState] = useState();

// Use the previous obj value if the "id" property hasn't changed
const objFinal = useMemoCompare(obj, (prev, next) => {
return prev && prev.id === next.id;
});

// Here we want to fire off an effect if objFinal changes.
// If we had used obj directly without the above hook and obj was technically a
// new object on every render then the effect would fire on every render.
// Worse yet, if our effect triggered a state change it could cause an endless loop
// where effect runs -> state change causes rerender -> effect runs -> etc ...
useEffect(() => {
// Call a method on the object and set results to state
return objFinal.someMethod().then((value) => setState(value));
}, [objFinal]);

// So why not pass [obj.id] as the dependency array instead?
useEffect(() => {
// Then eslint-plugin-hooks would rightfully complain that obj is not in the
// dependency array and we'd have to use eslint-disable-next-line to work around that.
// It's much cleaner to just get the old object reference with our custom hook.
return obj.someMethod().then((value) => setState(value));
}, [obj.id]);

return <div> ... </div>;
}

// Hook
function useMemoCompare<T>(
next: T,
compare: (prev: T | undefined, next: T) => boolean
): T | undefined {
// Ref for storing previous value
const previousRef = useRef<T | undefined>();
const prev = previousRef.current;
// Pass previous and next value to compare function
// to determine whether to consider them equal.
const isEqual = compare(prev, next);
// If not equal update previousRef to next value.
// We only update if not equal so that this hook continues to return
// the same old value if compare keeps returning true.
useEffect(() => {
if (!isEqual) {
previousRef.current = next;
}
});

return isEqual ? prev : next;
}
```