Skip to content

Instantly share code, notes, and snippets.

@andrewfulton
Created August 25, 2019 02:19
Show Gist options
  • Save andrewfulton/eb8d96134e815b2062791c814f884bd6 to your computer and use it in GitHub Desktop.
Save andrewfulton/eb8d96134e815b2062791c814f884bd6 to your computer and use it in GitHub Desktop.
I feel like I am so close to getting this...
import React, { useState, useCallback, useMemo } from 'react';
// Everyone loves an increment clicker component.
const Component = ({ id, value, onClick}) => {
console.log(`Hello lets render component ${id}`);
return (
<label>{value}
<button onClick={onClick}>Click</button>
</label>
);
}
// And we might love a memoized HOC version of
// it more (for later)
const MemoComponent = React.memo(Component);
const App = () => {
console.log('Its me, react, I am rendering App');
const [v1, setV1] = useState(0);
const [v2, setV2] = useState(0);
// Using useCallback like this (without array of dependencies)
// will basically do nothing and serves no purpose?
// const CBincreaseV1 = useCallback(()=>{ setV1(v1+1) } );
// const CBincreaseV2 = useCallback(()=>{ setV2(v2+1) } );
// Using the following version we will get a new function each time the
// tracked variable changes:
// const CBincreaseV1 = useCallback(()=>{ setV1(v1+1) }, [v1] );
// const CBincreaseV2 = useCallback(()=>{ setV2(v2+1) }, [v2] );
// Which is probably fine OR we could use this form,
// where we pass a function to the stateSetter()
// and will get a cached version every subsequent render forever:
const CBincreaseV1 = useCallback(()=>{ setV1(c => c + 1) }, [] );
const CBincreaseV2 = useCallback(()=>{ setV2(c => c + 1) }, [] );
// the WRONG version of this looks like this, as the function is cached
// forever, the value of v1/v2 is trapped/baked in through JS function closures:
// const CBincreaseV1 = useCallback(()=>{ setV1(v1+1) }, [] );
// const CBincreaseV2 = useCallback(()=>{ setV2(v2+1) }, [] );
// So those seem functionally equivalent, depending on whether
// you have other needs w/r/t referential equality of the CBincrease
// between renders
// BUT either way, the components will re-render themselves all the time
// anyway, unless we make a memoized version of them?
// ie this will always re-render both components:
// return (
// <>
// <Component id="One" value={v1} onClick={CBincreaseV1} />
// <Component id="Two" value={v2} onClick={CBincreaseV2} />
// </>
// )
// SO THEN the following will only re-render the children where any of
// the relevant props change (no unnecessary renders).
// For large trees or complex components this may matter. Here is absolutely
// does not.
// ALSO this uses React.memo to make a HOC, not useMemo which
// seems to be an entirely different thing perhaps just a much
// simpler cache of values ?
// eg const cached = useMemo(() => runAGreatBigWeatherSimulationBasedOnMyPropForSomeReason(v1), [v1]);
return (
<>
<MemoComponent id="One" value={v1} onClick={CBincreaseV1} />
<MemoComponent id="Two" value={v2} onClick={CBincreaseV2} />
</>
)
}
export default App;
npx degit portablestudios/minimally-react usecallback
# replace App.jsx with the below
npm install && npm start
# What is the use case for useCallback without memoization?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment