Functional programming's higher order method
Ref:
https://betterprogramming.pub/how-to-allow-only-one-click-events-in-javascript-72938027fbf5
Gist:
const once = (f) => { let finished = false; return (...args) => { if (!finished) { finished = true; f(...args); } }; };
Complete example:
- clicker 0 will fire events on every click.
- this is the problematic one.
- this can cause extra triggers to server-side if the network is slow and the user clicks again hoping the data will be submitted faster.
- clicker 1 will only fire again, after the button itself and the click function ref is re-rendered.
- this is a simple solution if we have to re-render the main component after the server has responded.
- clicker 2 will only fire again when value2 has any changes.
- if we want to control using specific state
import "./App.css"; import { useState, useCallback } from "react"; const once = (f) => { let finished = false; return (...args) => { if (!finished) { finished = true; f(...args); } }; }; function App() { const [value1, setValue1] = useState("value1"); const [value2, setValue2] = useState("value2"); console.log(`app rendered`); const onChange1 = useCallback((e) => { console.log(`onChange1`, e.target.value); setValue1(e.target.value); }, []); const onChange2 = useCallback((e) => { console.log(`onChange2`, e.target.value); setValue2(e.target.value); }, []); const onClick0 = () => { // mocking 2 secs network request setTimeout(() => { // set value to value1 to cause the re-render setValue1(new Date()); console.log("clicker 0"); }, 2000); }; const onClick1 = () => { // mocking 2 secs network request setTimeout(() => { // set value to value1 to cause the re-render setValue1(new Date()); console.log("clicker 1"); }, 2000); }; const onClick2 = () => { // mocking 2 secs network request setTimeout(() => { // set value to value1 to cause the re-render setValue1(new Date()); console.log("clicker 2"); }, 2000); }; const memoOnceOnClick2 = useCallback(once(onClick2), [value2]); return ( <div className="App"> <header className="App-header"> <input value={value1} onChange={onChange1} /> <input value={value2} onChange={onChange2} /> <button onClick={onClick0}> clicker 0 / run every time i am clicked </button> <button onClick={once(onClick1)}> clicker 1 / run once until i am re-render </button> <button onClick={memoOnceOnClick2}> clicker 2 / run once until value2 is changed </button> </header> </div> ); } export default App;
.oneto do something like clear a dropdown.