Your post enlightened me a lot.
I wrote a simpler function based on your idea. On TypeScript, this style may be preferable since different handlers can have different types. codesandbox.io/s/react-usehandler-...
/* based on https://dev.to/anpos231/react-hooks-the-closure-hell-2-58g9 */importReact,{useState,useRef,memo}from"react";importReactDOMfrom"react-dom";import"./styles.css";constuseHandler=preHandler=>{letref=useRef({altHandler:null,handler:null});if(!ref.current.handler){ref.current.handler=(...args)=>ref.current.altHandler(...args);}ref.current.altHandler=preHandler;returnref.current.handler;};lettimes=0;constExpensiveComponent=memo(({onClick})=>(<ponClick={onClick}>re-render: {times++}</p>));constApp=()=>{const[value,setValue]=useState(1);consthandleClick=useHandler(_=>{setValue(value+1);});/* instead of
const handleClick = _ => {
setValue(value + 1);
};
*/return(<divclassName="app"><ExpensiveComponentonClick={handleClick}/><buttononClick={handleClick}>increment value</button><p>{value}</p></div>);};constrootElement=document.getElementById("root");ReactDOM.render(<App/>,rootElement);
In this particular situation, if we pass an update function to setValue instead, it suffices to simply use useCallback with an empty dependency list. (Notably, useCallback((...) => ..., []) is equivalent to useRef((...) => ...).current.)
/* based on https://dev.to/anpos231/react-hooks-the-closure-hell-2-58g9 */importReact,{useState,useRef,memo}from"react";importReactDOMfrom"react-dom";import"./styles.css";lettimes=0;constExpensiveComponent=memo(({onClick})=>(<ponClick={onClick}>re-render: {times++}</p>));constApp=()=>{const[value,setValue]=useState(1);consthandleClick=useCallback(_=>{setValue(value=>value+1);},[]);return(<divclassName="app"><ExpensiveComponentonClick={handleClick}/><buttononClick={handleClick}>increment value</button><p>{value}</p></div>);};constrootElement=document.getElementById("root");ReactDOM.render(<App/>,rootElement);
Your post enlightened me a lot.
I wrote a simpler function based on your idea. On TypeScript, this style may be preferable since different handlers can have different types.
codesandbox.io/s/react-usehandler-...
In this particular situation, if we pass an update function to setValue instead, it suffices to simply use useCallback with an empty dependency list. (Notably,
useCallback((...) => ..., [])
is equivalent touseRef((...) => ...).current
.)So are you saying that we can function to setValue? And it will call it with the current state? Just like the old this.setState()?
How could I miss it!