Table of contents
Open Table of contents
useContext
Example:
Single file config
App.js
import "./App.css"; import { Routes, Route } from "react-router-dom"; import Pages from "./pages/page"; import Layout from "./layout"; import LoginPage from "./loginPage"; import RegisterPage from "./registerPage"; import { UserContextProvider } from "./context/userContext"; import CreatePost from "./pages/createPost"; import PostPage from "./pages/postPage"; import AuthorPage from "./pages/authorPage"; import EditPost from "./pages/editPost"; const App = () => { return ( <UserContextProvider> <Routes> <Route path="/" element={<Layout />}> <Route index element={<Pages />} /> <Route path={"/login"} element={<LoginPage />} /> <Route path={"/register"} element={<RegisterPage />} /> <Route path={"/create"} element={<CreatePost />} /> <Route path={"/post/:id"} element={<PostPage />} /> <Route path={"/author/:id"} element={<AuthorPage />} /> <Route path={"/editPost/:id"} element={<EditPost />} /> </Route> </Routes> </UserContextProvider> ); }; export default App;
UserContext.js
import { createContext, ReactNode, useContext } from 'react' import { useState } from 'react' type UserProps = { username: string; id: string; iat?: number; cover?: string; content?: string; } type ContextProps = { userInfo: UserProps | null setUserInfo: React.Dispatch<React.SetStateAction<UserProps | null>> } const UserContext = createContext<ContextProps>({ userInfo: null, setUserInfo: () => { } }) export const useUserContext = () => useContext(UserContext); export function UserContextProvider({ children }: { children: ReactNode }) { const [userInfo, setUserInfo] = useState<UserProps | null>(null) return ( <UserContext.Provider value={{ userInfo, setUserInfo }}> {children} </UserContext.Provider>) }
To Access user
const { userInfo, setUserInfo } = useUserContext();
Two file config
DataContext.js
import { createContext } from "react"; const DataContext = createContext(); export default DataContext;
DataState.js
import React, { useState } from "react"; import DataContext from "./DataContext"; const DataState = props => { const [btnState, setBtnState] = useState(false); return ( <DataContext.Provider value={{ btnState, setBtnState }}> {props.children} </DataContext.Provider> ); }; export default DataState;
App.js
import "./App.scss"; import DataState from "./Components/DataState"; import Example from "./ExampleComponent" function App() { return ( <div className="App"> <DataState> <h3>Hello</h3> <Example> </DataState> </div> ); } export default App;
Then in Example.js component where you have to use context
import React, { useContext } from "react"; import DataContext from "./DataContext"; const Example = props => { const {btnState, setBtnState} = useContext(DataContext); return ( <div> <button onClick={()={setBtnState(!btnState)}}>Click me</button> </div> ); }; export default Example;
useReducer
example:
ReducerHelper.js
import { useReducer } from "react"; const initialState = { count: 0 }; function reducer(state, action) { switch (action.type) { case "increment": return { count: state.count + 1 }; case "decrement": return { count: state.count - 1 }; default: throw new Error(); } } const ReducerHelper = () => { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({ type: "increment" })}>+</button> <button onClick={() => dispatch({ type: "decrement" })}>-</button> </> ); }; export default ReducerHelper;
useMemo
example:
MemoHelper.js
import { useMemo, useState } from "react"; const delayFunction = dayOrNight => { const start = Date.now(); let i = 0; while (i < 10000) { i += 0.0001; } const end = Date.now(); console.log(`Execution time: ${end - start} ms`); if (dayOrNight === "") return ""; if (dayOrNight === "morning") return "Good morning"; else return "Just sleep"; }; const MemoHelper = () => { const [dayOrNight, setDayOrNight] = useState(""); const [theme, setTheme] = useState(false); // const greeting = delayFunction(dayOrNight) //toggle to see effect of having an expensize function run without useMemo const greeting = useMemo(() => { return delayFunction(dayOrNight); }, [dayOrNight]); return ( <div> <fieldset> <legend style={theme ? { color: "green" } : { color: "red" }}> Type something and check delay in console? </legend> <input type="text" value={dayOrNight} onChange={e => setDayOrNight(e.target.value)} /> </fieldset> <div style={theme ? { color: "green" } : { color: "red" }}> <p>Greeting:- {greeting}</p> </div> <button onClick={() => setTheme(!theme)}>Change Color</button> <p> Buttton click causes re-render of component but delayFunction only runs if dependency changes </p> </div> ); }; export default MemoHelper;
useCallback
example:
CallbackParent.js
import { useCallback, useState } from "react"; import CallbackChild from "./CallbackChild"; const CallbackParent = () => { const [number, setNumber] = useState(0); const [dark, setDark] = useState(false); console.log("Parent Component redered"); const handler = useCallback(() => { return [number, number + 1, number + 2]; }, [number]); //api function call //const handler = ()=> { return [number, number + 1, number + 2]} //toggle this api* function to see it run on every render on parent without useCallback hook const theme = { backgroundColor: dark ? "#333" : "#fff", color: dark ? "#fff" : "#333", }; return ( <> <div style={theme}> <input type="number" value={number} onChange={e => setNumber(parseInt(e.target.value))} /> <button onClick={() => setDark(prevDark => !prevDark)}> Toggle theme </button> <CallbackChild handler={handler} /> </div> </> ); }; export default CallbackParent;
CallbackChild.js
import { useEffect, useState } from "react"; const CallbackChild = ({ handler }) => { const [items, setItems] = useState([]); useEffect(() => { setItems(handler()); console.log("Child Component redered"); }, [handler]); return ( <> {items.map((item, index) => { return <div key={index}>{item}</div>; })} </> ); }; export default CallbackChild;
Note:
Remember useMemo and useCallback both take advantage of Referential Equality and they do have benifits & related side effects. Therefore, use them only when their use causes significant performence gain. useMemo return result, whereas useCallback returns a callback function which can take an argument too, passed from the child component. Both have similar syntax.
useNavigate
Install
useNavigate is part of react-router-dom hence we need to install that in order to use this hook
npm i react-router-dom
Usage
import { useNavigate } from "react-router-dom"; export default app = () => { const navigate = useNavigate(); useEffect(() => { setTimeout(() => { // 👇 Redirects to home page, note the `replace: true` navigate("/", { replace: true }); }, 3000); }, []); return <p>redirect home in 3 secs</p>; };
useSearchParams
Installation useSearchParams is part of react-router-dom
npm i react-router-dom
Example
import { useSearchParams } from "react-router-dom"; import "./App.css"; function App() { const items = [ "apple", "banana", "car", "dog", "elephant", "flower", "guitar", "house", ]; const [search, setSearch] = useSearchParams({ q: "" }); const query = search.get("q") || ""; const filtered = items.filter(item => item.includes(query)); return ( <> <h1 className="text-[20px] text-blue-600">Hello react + vite app</h1> <div> <label htmlFor="q">Title</label> <input className="border-2 m-2 pl-1" type="text" id="q" value={query} onChange={e => setSearch( prev => { prev.set("q", e.target.value); return prev; }, { replace: true } // backbutton takes user to previous page ) } /> </div> <h1 className="font-semibold">Items</h1> <ul> {filtered.map(item => ( <li key={item} className="list-disc"> {item} </li> ))} </ul> </> ); } export default App;