Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
React Hook recipe from https://usehooks.com
import React, { useState, useEffect, useRef } from 'react';
// Usage
function MyComponent({ obj }) {
const [state, setState] = useState();
// We want the previous obj if obj.id is the same as the new obj.id
// We pass a custom equality function as the second arg to our hook.
const theObj = useMemoCompare(obj, prev => prev && prev.id === obj.id);
// Here we want to fire off an effect if theObj 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.
// (effect runs -> state change causes rerender -> effect runs -> etc ...)
useEffect(() => {
// Call a method on the object and set results to state
return theObj.someMethod().then((value) => setState(value));
}, [theObj]);
// So why not just pass [obj.id] as dependecy array?
useEffect(() => {
// Well, then eslint-plugin-hooks would rightfully complain that obj is not in the
// dependency array. By using our hook above we are more explicit about our custom
// equality checking and can separate that concern from that of our effect logic.
return obj.someMethod().then((value) => setState(value));
}, [obj.id]);
return <div> ... </div>;
}
// Hook
function useMemoCompare(value, compare) {
// Ref for storing previous value
const previousRef = useRef();
const previous = previousRef.current;
// Pass previous and new value to compare function
const isEqual = compare(previous, value);
// If not equal update previous to new value (for next render)
// and then return new new value below.
useEffect(() => {
if (!isEqual) {
previousRef.current = value;
}
});
return isEqual ? previous : value;
}
@zarcode

This comment has been minimized.

Copy link

zarcode commented Apr 9, 2020

It seams to me that your compare function prev => prev && prev.id === obj.id accepts only one argument, but later on you are calling it with two compare(previous, value)

@gragland

This comment has been minimized.

Copy link
Owner Author

gragland commented Apr 10, 2020

It seams to me that your compare function prev => prev && prev.id === obj.id accepts only one argument, but later on you are calling it with two compare(previous, value)

In this example, since the compare function is defined inline, I already have obj in scope so don't need to use the second arg. If the function was extracted out though I'd need that arg.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.