10 React Hooks Explained // Plus Build your own from Scratch
Last active
June 1, 2024 04:51
-
-
Save savio777/057168ec69159e3f8ac2eac469e132a9 to your computer and use it in GitHub Desktop.
React Hooks
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
import useCount from "./useCount"; | |
function App() { | |
const { | |
count, | |
handleAddCount, | |
countRef, | |
handleAddCountRef, | |
reducer, | |
expensiveCount, | |
} = useCount(); | |
const divRef = useRef<HTMLDivElement>(null); | |
// useLayoutEffect | |
useLayoutEffect(() => { | |
const rect = divRef.current?.getBoundingClientRect(); | |
console.log("div height: ", rect.height); | |
}, []); | |
return ( | |
<> | |
<h1>React Hooks</h1> | |
<div className="card"> | |
<button onClick={handleAddCount}>count is {count}</button> | |
<button onClick={handleAddCountRef}> | |
count ref is {countRef.current} | |
</button> | |
<button onClick={() => reducer.dispatch({ type: "add" })}> | |
count reducer is {reducer.state} | |
</button> | |
<button> | |
expensive count {expensiveCount.toFixed(2).replace(".", ",")} | |
</button> | |
</div> | |
</> | |
); | |
} | |
export default App; |
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
import React from "react"; | |
import ReactDOM from "react-dom/client"; | |
import App from "./App.tsx"; | |
import "./index.css"; | |
import { CountProvider } from "./useCount.tsx"; | |
ReactDOM.createRoot(document.getElementById("root")!).render( | |
<React.StrictMode> | |
<CountProvider> | |
<App /> | |
</CountProvider> | |
</React.StrictMode> | |
); |
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
/* eslint-disable react-refresh/only-export-components */ | |
import { | |
Dispatch, | |
MutableRefObject, | |
ReactNode, | |
createContext, | |
useCallback, | |
useContext, | |
useDebugValue, | |
useEffect, | |
useMemo, | |
useReducer, | |
useRef, | |
useState, | |
} from "react"; | |
const INITIAL_COUNT = 0; | |
interface Props { | |
children: ReactNode; | |
} | |
interface IActionPayloadReducer { | |
type: "add" | "decrease"; | |
} | |
interface IValues { | |
count: number; | |
countRef: MutableRefObject<number>; | |
handleAddCountRef: () => void; | |
handleAddCount: () => void; | |
expensiveCount: number; | |
reducer: { | |
state: number; | |
dispatch: Dispatch<IActionPayloadReducer>; | |
}; | |
} | |
const reducer = (state: number, action: IActionPayloadReducer) => { | |
switch (action.type) { | |
case "add": | |
return state + 1; | |
case "decrease": | |
return state - 1; | |
default: | |
return state; | |
} | |
}; | |
// context | |
export const CountContext = createContext<IValues>({} as IValues); | |
export const CountProvider = ({ children }: Props) => { | |
// useContext | |
console.log("context count"); | |
// useState | |
const [count, setCount] = useState(INITIAL_COUNT); | |
const handleAddCount = useCallback(() => { | |
setCount((oldValue) => oldValue + 1); | |
}, []); | |
// useDebugValue | |
useDebugValue(count || "0 count"); // use with 'React Developer Tools' plugin | |
// useRef | |
const countRef = useRef(0); | |
const handleAddCountRef = () => countRef.current++; // don't re render on action | |
// useReducer | |
const [state, dispatch] = useReducer(reducer, INITIAL_COUNT); | |
// useMemo | |
const expensiveCount = useMemo(() => count * Math.random() * 10, [count]); | |
// useEffect | |
useEffect(() => { | |
const initData = async () => { | |
try { | |
const response = await fetch("https://api.github.com/users/savio777"); | |
const responseJson = await response.json(); | |
console.log("execute when component did mount", responseJson); | |
} catch (error) { | |
console.log({ error }); | |
} | |
}; | |
initData(); | |
}, []); | |
useEffect(() => { | |
console.log("with each status update: ", count); | |
// execute when dismount | |
/* | |
return () => { | |
setCount(0); | |
}; | |
*/ | |
}, [count]); | |
return ( | |
<CountContext.Provider | |
value={{ | |
count, | |
handleAddCount, | |
countRef, | |
handleAddCountRef, | |
expensiveCount, | |
reducer: { | |
dispatch, | |
state, | |
}, | |
}} | |
> | |
{children} | |
</CountContext.Provider> | |
); | |
}; | |
const useCount = (): IValues => { | |
const context = useContext(CountContext); | |
if (!context) { | |
throw new Error("useI18N must be used within an I18nProvider"); | |
} | |
return context; | |
}; | |
export default useCount; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment