Last active
September 21, 2020 23:53
-
-
Save peerreynders/87bc7702a9da7c5c5392dc8d05f7df9a to your computer and use it in GitHub Desktop.
useRefreshCallback - custom hook that also avoids creating garbage functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="eng"> | |
<head> | |
<meta charset="utf-8"/> | |
<title>useCallback alternative BEFORE</title> | |
</head> | |
<body> | |
<script type="module"> | |
import { | |
html, render, useState, useCallback | |
} from '//unpkg.com/htm/preact/standalone.mjs'; | |
// Component Parts | |
const initialDelta = 1; | |
const incDelta = delta => delta + 1; | |
const initialCount = 0; | |
// Component | |
// contrived use of useCallback - "cost of checks" yada, yada | |
function App() { | |
const [delta, setDelta] = useState(initialDelta); | |
const [count, setCount] = useState(initialCount); | |
// useCallback avoids the changing props value | |
// issue of newly created functions that don't behave | |
// differently - but is doesn't address creating garbage | |
// (i.e. unnecessary) functions on the majority of calls | |
// | |
const stepDelta = useCallback(() => setDelta(incDelta), []); | |
const stepCount = useCallback(() => setCount(count => count + delta), [delta]); | |
return html` | |
<p> | |
<button onClick=${stepDelta}>Step Delta</button> | |
<button onClick=${stepCount}>Step</button> | |
</p> | |
<output>Delta: ${delta} Count: ${count}</output> | |
`; | |
} | |
render(html`<${App} />`, document.body); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="eng"> | |
<head> | |
<meta charset="utf-8"/> | |
<title>useCallback alternative AFTER</title> | |
</head> | |
<body> | |
<script type="module"> | |
import { | |
html, render, useState | |
} from '//unpkg.com/htm/preact/standalone.mjs'; | |
// custom hook | |
function useRefreshCallback(refreshCallback, isEqual, deps) { | |
const [state, setCallback] = useState(null); | |
if (state !== null && isEqual(state.lastDeps, deps)) { | |
return state.callback; | |
} | |
const fresh = refreshCallback(deps); | |
setCallback({callback: fresh, lastDeps: deps}); | |
return fresh; | |
} | |
// Component Parts | |
const initialDelta = 1; | |
const incDelta = delta => delta + 1; | |
const refreshDeltaCallback = ([setDelta]) => { | |
console.log('refresh delta callback'); | |
return () => setDelta(incDelta); | |
}; | |
const initialCount = 0; | |
const refreshCountCallback = ([delta, setCount]) => { | |
console.log('refresh count callback with delta:', delta); | |
const incCount = count => count + delta; | |
return () => setCount(incCount); | |
}; | |
// Shallow comparison is good enough in **this** case | |
function depsEqual(oldDeps, deps) { | |
if (oldDeps.length !== deps.length) { | |
return false; | |
} | |
for (let i = 0; i < deps.length; ++i) { | |
if (oldDeps[i] !== deps[i]) { | |
return false; | |
} | |
} | |
return true; | |
} | |
// Component | |
// contrived use of useRefreshCallback - "cost of checks" yada, yada | |
function App() { | |
const [delta, setDelta] = useState(initialDelta); | |
const [count, setCount] = useState(initialCount); | |
// call `refreshCallback` function only if dependencies change | |
const stepDelta = useRefreshCallback(refreshDeltaCallback, depsEqual, [setDelta]); | |
const stepCount = useRefreshCallback(refreshCountCallback, depsEqual, [delta, setCount]); | |
return html` | |
<p> | |
<button onClick=${stepDelta}>Step Delta</button> | |
<button onClick=${stepCount}>Step</button> | |
</p> | |
<output>Delta: ${delta} Count: ${count}</output> | |
`; | |
} | |
render(html`<${App} />`, document.body); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment