I have only recently begun to understand what macros are in a Lisp context. My understanding is that basically, the code is executed in two passes. In the first pass, the interpreter identifies calls to macros and replaces them with their return values. Second, it executes the code normally.
This looks like what happens with custom hooks in React. For example, if you have the useOnlineStatus
hook:
function useOnlineStatus() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { function handleOnline() { setIsOnline(true); } function handleOffline() { setIsOnline(false); } window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); return isOnline; }
This is like a macro. If you use the useOnlineStatus
hook like this:
const isOnline = useOnlineStatus();
This is like a call to a macro. So if you have:
function StatusBar() { const isOnline = useOnlineStatus(); return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>; }
After the first pass, it is converted to:
function StatusBar() { const [isOnline, setIsOnline] = useState(true); useEffect(() => { function handleOnline() { setIsOnline(true); } function handleOffline() { setIsOnline(false); } window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); return <h1>{isOnline ? '✅ Online' : '❌ Disconnected'}</h1>; }
Then it will execute normally on the second pass. Is this an accurate model of what happens with custom hooks?
If you squint, it looks a bit like that, but with a few points:
While the browser does perform multiple passes to parse and then execute JavaScript, calling a hook is not an example of this. Therefore, running the component requires only one pass, running line by line, and stepping into the function when the instruction is encountered.
The same mental model can be applied to every function call. When you call:
You can think of it as unpacking the code in Math.max and putting it into your main function. But that's not actually how it works.