What is it good for?
function getDimensions() { const { innerWidth: width, innerHeight: height } = window; return { width, height }; } export function MyComponent() { const [windowDimensions, setWindowDimensions] = useState(getDimensions()); const handleResize = useCallback(() => { setWindowDimensions(getDimensions()); }, []); useEffect(() => { console.log("useEffect: Evaluated"); handleResize(); window.addEventListener('resize', handleResize); return () => { console.log("useEffect: Cleanup evaluated"); window.removeEventListener('resize', handleResize); }; }, [handleResize]); }
function getDimensions() { const { innerWidth: width, innerHeight: height } = window; return { width, height }; } export function MyComponent() { const [windowDimensions, setWindowDimensions] = useState(getDimensions()); const handleResize = useCallback(() => { setWindowDimensions(getDimensions()); }, []); useEffect(() => { console.log("useEffect: Evaluated"); handleResize(); window.addEventListener('resize', handleResize); return () => { console.log("useEffect: Cleanup evaluated"); window.removeEventListener('resize', handleResize); }; }, [handleResize]); }
function getDimensions() { const { innerWidth: width, innerHeight: height } = window; return { width, height }; } export function MyComponent() { const [windowDimensions, setWindowDimensions] = useState(getDimensions()); const handleResize = useCallback(() => { setWindowDimensions(getDimensions()); }, []); useEffect(() => { console.log("useEffect: Evaluated"); handleResize(); window.addEventListener('resize', handleResize); return () => { console.log("useEffect: Cleanup evaluated"); window.removeEventListener('resize', handleResize); }; }, [handleResize]); }
function getDimensions() { const { innerWidth: width, innerHeight: height } = window; return { width, height }; } export function MyComponent() { const [windowDimensions, setWindowDimensions] = useState(getDimensions()); const handleResize = useCallback(() => { setWindowDimensions(getDimensions()); }, []); useEffect(() => { console.log("useEffect: Evaluated"); handleResize(); window.addEventListener('resize', handleResize); return () => { console.log("useEffect: Cleanup evaluated"); window.removeEventListener('resize', handleResize); }; }, [handleResize]); }
What's going on here?
index.tsx
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( <React.StrictMode> <App /> </React.StrictMode> );
In development, when using Strict Mode , components are remounted: mount, unmount, mount.
Purpose: future-proofing the app.
Purpose: future-proofing the app
We can reuse a concrete Hook logic by extracting it into a
custom Hook.
function MyComponent() { const result = /* logic that uses Hooks */ return <p>{result}</p>; }
The logic to be extracted can use a single or multiple Hooks.
We simply move the logic into its own function.
function useMyCustomHook() { /* logic that uses Hooks */ return result; } function MyComponent() { const result = useMyCustomHook(); return <p>{result}</p>; }
function useMyCustomHook() { /* logic that uses Hooks */ return result; } function MyComponent() { const result = useMyCustomHook(); return <p>{result}</p>; }
function useMyCustomHook() { /* logic that uses Hooks */ return result; } function MyComponent() { const result = useMyCustomHook(); return <p>{result}</p>; }
In the component we then call this function.
Stick to the Hooks naming convention: use*
/* logs the paste event to the console */
window.addEventListener("paste", console.log);
/* returns the clipboard text */
(e: ClipboardEvent) => e.clipboardData?.getData("Text")
/* get the form setValue function */
const { setValue } = useForm<FormValues>();
useWindowPaste.ts
export function useWindowPaste(onPasted: (value: string) => void) { const handlePaste = useCallback( (event: ClipboardEvent) => { const value = event.clipboardData?.getData("Text"); value && onPasted(value); }, [onPasted] ); useEffect(() => { window.addEventListener("paste", handlePaste); return () => window.removeEventListener("paste", handlePaste); }, [handlePaste]); }
export function useWindowPaste(onPasted: (value: string) => void) { const handlePaste = useCallback( (event: ClipboardEvent) => { const value = event.clipboardData?.getData("Text"); value && onPasted(value); }, [onPasted] ); useEffect(() => { window.addEventListener("paste", handlePaste); return () => window.removeEventListener("paste", handlePaste); }, [handlePaste]); }
export function useWindowPaste(onPasted: (value: string) => void) { const handlePaste = useCallback( (event: ClipboardEvent) => { const value = event.clipboardData?.getData("Text"); value && onPasted(value); }, [onPasted] ); useEffect(() => { window.addEventListener("paste", handlePaste); return () => window.removeEventListener("paste", handlePaste); }, [handlePaste]); }
Profile.tsx
export function Profile() { const { register, handleSubmit, formState: { errors }, setValue, } = useForm<FormValues>(); const onSubmit: SubmitHandler<FormValues> = (data) => console.log(data); useWindowPaste((value) => setValue("name", `Dr. ${value}`)); /* … */ }
export function Profile() { const { register, handleSubmit, formState: { errors }, setValue, } = useForm<FormValues>(); const onSubmit: SubmitHandler<FormValues> = (data) => console.log(data); useWindowPaste((value) => setValue("name", `Dr. ${value}`)); /* … */ }
We learned…