Skip to content

Instantly share code, notes, and snippets.

@ricokahler
Created September 19, 2019 03:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ricokahler/c207aaadc42de3a133490b24c4dddd64 to your computer and use it in GitHub Desktop.
Save ricokahler/c207aaadc42de3a133490b24c4dddd64 to your computer and use it in GitHub Desktop.
Only add the event listener once
import React, { useCallback } from 'react';
function usePullValue(value) {
const ref = useRef(value);
useLayoutEffect(() => {
ref.current = value;
}, [value]);
return useCallback(() => {
return ref.current;
}, [])
}
function MyComponent() {
const ref = useRef();
const [someUpdatingValue, setSomeUpdatingValue] = useState(0);
const getSomeUpdatingValue = usePullValue(someUpdatingValue);
useEffect(() => {
const el = ref.current;
const handler = () => {
const someUpdatingValue = getSomeUpdatingValue();
// do something with _latest_ `someUpdatingValue`
};
el.addEventListener('click', handler);
return () => {
el.removeEventListener('click', handler);
};
}, [getSomeUpdatingValue]);
return <div ref={ref}>{/* blah */}</div>;
}
export default MyComponent;
@ricokahler
Copy link
Author

There's also a simpler use case for usePullValue which is just removing reactivity of a dependency of an effect.

function Counters() {
  const [a, setA] = useState(0);
  const [b, setB] = useState(0);

  const getB = usePullValue(b);

  // this effect only fires when `a` changes and `react-hooks/exhaustive-deps` doesn't yell at me
  useEffect(() => {
    const latestB = getB();
    setA(a + latestB);
  }, [a, getB]);

  return // ...
}

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