Skip to content

Instantly share code, notes, and snippets.

@dwighthouse
Created September 11, 2019 20:31
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save dwighthouse/bef9d4161f4255a9f7a060fabd0a3240 to your computer and use it in GitHub Desktop.
Using This-Like Ref Structure to Solve Hook State Updating and Function Reference Problems
import React, { memo, useCallback } from 'react';
import ChildComponent from './wherever/ChildComponent.js';
const updateChild = (props, childId, changes) => {
props.onUpdate({
type: 'childChanged',
childId: childId,
changes: changes,
});
};
function ThisLikeExample(props) {
const thisLike = React.useRef();
thisLike.current = props;
// Do something with state changes using the "thisLike" ref reference to get the most up-to-date props
// Note the intentionally empty dependency arrays on these callbacks, meaning the function references will never change
// NEVER use props directly inside a callback for useCallback, useEffect, etc.
const onUpdateChild1 = useCallback((changes) => {
updateChild(thisLike.current, 'child1', changes);
}, []);
const onUpdateChild2 = useCallback((changes) => {
updateChild(thisLike.current, 'child2', changes);
}, []);
// Assuming ChildComponent is memo'd, will only re-render if their state prop reference changes, the function references never change
// This architecture benefits most from an immutable style so that all data equality can be determined by reference equality
return (
<div>
<ChildComponent state={props.state.child1} onUpdate={onUpdateChild1} />
<ChildComponent state={props.state.child2} onUpdate={onUpdateChild2} />
</div>
);
}
export default memo(ThisLikeExample);
@jesseko
Copy link

jesseko commented Jan 15, 2021

Thanks for this!

Your comment here was helpful to explain this:
(copying here in case useful to others)

I skirt around the problem of stale state by setting a ref at the top of the function that contains whatever the props are that render. Since ref references don’t change from render to render, referencing the ref-contained props inside my useEffect or useCallback always returns the most up to date props. That also means that the dependency arrays for these functions are always empty, the functions only ever created once, which prevents additional unnecessary rerendering of children due to changed function references. The only requirement is that the functions I use inside useEffect and friends have to use props through the ref reference.

Effectively, I created a managed “this” variable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment