The Ultimate Knowledge Hub
Explanation:
React re-renders components when props or state change. To avoid unnecessary re-renders, use:
React.memo() to memoize components.
useMemo() to memoize computed values.
useCallback() to memoize functions.
This prevents React from re-rendering unless necessary, improving performance.
const MemoComponent = React.memo(({ value }) => {
console.log("Rendered");
return <div>{value}</div>;
});
Only re-renders when value changes.
Explanation:
Debouncing means waiting a short time (like 300ms) before executing a function. It's useful for API calls when typing — so the API is only called after the user stops typing.
const debounce = (fn, delay) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
};
const fetchData = debounce((query) => {
fetch(`/api?q=${query}`);
}, 300);
Executes only after 300ms of no input.
useMemo?Explanation:
If a function takes a lot of time (like looping 1000s of times), React may re-run it on every render. useMemo() remembers the result until inputs change, saving time.
const result = useMemo(() => expensiveCalc(num), [num]);
Explanation:
Infinite scroll means loading more data as you scroll down the page. You can do this by placing a div at the bottom and using IntersectionObserver to check when it becomes visible — then fetch more data.
Explanation:
Throttling allows a function to run only once in a set time (e.g., once every second), no matter how often the user clicks. This prevents too many fast clicks from triggering the same action.
const throttle = (fn, delay) => {
let last = 0;
return (...args) => {
const now = Date.now();
if (now - last > delay) {
last = now;
fn(...args);
}
};
};
Explanation:
Instead of using useState, you can use useReducer to toggle between true/false. This makes the logic more maintainable in bigger apps.
Explanation:
Great for toggling boolean values with clear logic separation.
const reducer = (state) => !state;
const [on, toggle] = useReducer(reducer, false);
Explanation:
When a component is removed (unmounted), its state is lost. To keep the data, you can:
Move the state to a parent that stays mounted.
Save the state in localStorage or sessionStorage and reload it later.
useEffect(() => {
localStorage.setItem("form", JSON.stringify(formData));
}, [formData]);
Explanation:
If you add a global event (like keypress), always remove it when the component unmounts to prevent bugs and memory issues.
Explanation:
Always clean up side effects to prevent memory leaks.
useEffect(() => {
const handleKeyPress = e => console.log(e.key);
window.addEventListener('keypress', handleKeyPress);
return () => window.removeEventListener('keypress', handleKeyPress);
}, []);
Explanation:
You can create your own hook using useState and useEffect to track window size on resize and use it in any component.
Explanation:
Listens to window resize and updates dimensions.
function useWindowSize() {
const [size, setSize] = useState([window.innerWidth, window.innerHeight]);
useEffect(() => {
const handleResize = () => setSize([window.innerWidth, window.innerHeight]);
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return size;
}
Explanation:
This pattern helps you wait until a user stops typing before calling an API, and avoid unnecessary fetch calls during every keystroke.
Explanation:
Debounce inside useEffect avoids unnecessary API hits.
useEffect(() => {
const handler = setTimeout(() => {
if (search) fetchData(search);
}, 300);
return () => clearTimeout(handler);
}, [search]);
Explanation:
When a component is removed before an async fetch finishes, it can cause errors. Use AbortController to stop (abort) the fetch when the component unmounts.
useEffect(() => {
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal });
return () => controller.abort();
}, []);
Explanation:
You can put a check inside useEffect to run the effect only when certain conditions are met. This avoids extra fetches or actions.
Explanation:
Check condition inside useEffect to avoid unwanted runs.
useEffect(() => {
if (!userId) return;
fetch(`/api/user/${userId}`);
}, [userId]);
Explanation:
While data is loading, show a loading spinner. After data arrives, show the real content. This is common in API-heavy apps.
Explanation:
Use local state to track async status and conditionally render JSX.
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchData().then(() => setLoading(false));
}, []);
return loading ? <Spinner /> : <ActualComponent />;
Explanation:
Use useRef to store the old value and compare it in the next render. Helpful in debugging or triggering actions only on change.
Explanation:
Use a custom hook or useRef to store the previous value.
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
Explanation:
Use useRef() to grab the input element and useEffect() to focus on it right after the component is mounted.
Explanation:
Use useRef with useEffect.
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
}, []);
Explanation:
React’s useEffect with an empty dependency array ([]) runs only once — perfect for loading data on initial render.
Explanation:
Using useEffect with an empty dependency array ensures the effect runs only on first render.
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(setData);
}, []);
Explanation:
A stale closure happens when your async function uses outdated state. To avoid this, use functional updates or a reference (useRef) to always have the latest value.
const countRef = useRef(count);
useEffect(() => { countRef.current = count; }, [count]);
Explanation:
Use Promise.all() to run all API calls at the same time and wait for them to finish. Then update the state with all results together.
useEffect(() => {
Promise.all([
fetch('/api/users').then(res => res.json()),
fetch('/api/posts').then(res => res.json())
]).then(([users, posts]) => {
setUsers(users);
setPosts(posts);
});
}, []);
Explanation:
React.lazy() lets you load components only when needed. This reduces the initial load time. Wrap it in Suspense to show a loader until the component is ready.
const LazyComp = React.lazy(() => import('./LazyComp'));
<Suspense fallback={<div>Loading...</div>}>
<LazyComp />
</Suspense>
Explanation:
Use Context to share theme across components. Manage the theme state using useState and update it using a toggle function.
const ThemeContext = createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => setTheme(t => (t === 'light' ? 'dark' : 'light'));
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
Explanation:
Use useCallback() to save a function so that it doesn’t get recreated unless its dependencies (like props) change. This improves performance.
const handleClick = useCallback(() => {
console.log("Clicked", userId);
}, [userId]);
Explanation:
In complex apps, you may have separate pieces of state. Use multiple useReducer calls or a custom function to organize them cleanly.
const [state1, dispatch1] = useReducer(reducer1, init1);
const [state2, dispatch2] = useReducer(reducer2, init2);
Explanation:
Use useEffect(() => {}, []) to run logic only once. This is good for setup tasks like initializing state or calling an API on first load.
const [loaded, setLoaded] = useState(false);
useEffect(() => {
if (!loaded) {
doInitLogic();
setLoaded(true);
}
}, [loaded]);
Explanation:
Sometimes an async request finishes after the component is unmounted. Use a flag to check if it’s still safe to call setState.
useEffect(() => {
let isMounted = true;
fetch('/api/data').then(res => res.json()).then(data => {
if (isMounted) setData(data);
});
return () => { isMounted = false; };
}, []);
Explanation:
React Router provides useLocation(). You can detect route change and reset any form or local state as needed when the path changes.
const location = useLocation();
useEffect(() => {
setForm({}); // reset form when route changes
}, [location.pathname]);
Explanation:
Keep track of which tab is active using useState, and conditionally render different content based on the selected tab.
const [activeTab, setActiveTab] = useState("home");
return (
<>
<button onClick={() => setActiveTab("home")}>Home</button>
<button onClick={() => setActiveTab("about")}>About</button>
{activeTab === "home" && <Home />}
{activeTab === "about" && <About />}
</>
);
Explanation:
Sometimes you want to keep the app state even if the user reloads the page. You can store the state in localStorage or sessionStorage, and load it back on mount.
Explanation:
Use localStorage or sessionStorage to save state and retrieve on mount.
const [count, setCount] = useState(() => {
return Number(localStorage.getItem("count")) || 0;
});
useEffect(() => {
localStorage.setItem("count", count);
}, [count]);
Explanation:
React doesn’t handle keyboard events globally by default. Use useEffect to attach a listener and clean it up when the component unmounts.
Explanation:
Use useEffect to listen for keydown and clean up after unmounting.
useEffect(() => {
const handleKeyDown = (e) => {
if (e.key === 'Escape') closeModal();
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, []);
Explanation:
Animations make UI smoother. Use libraries like react-transition-group or CSS transitions to animate components when they appear or disappear.
Explanation:
Use react-transition-group or CSS animations.
import { CSSTransition } from 'react-transition-group';
<CSSTransition in={show} timeout={300} classNames="fade" unmountOnExit>
<div className="fade">Hello</div>
</CSSTransition>
Explanation:
When you fetch data, it might finish after the component is gone. To avoid memory leaks or errors, set a flag or use cleanup in useEffect.
Explanation:
Use a flag inside useEffect or use a cleanup function.
useEffect(() => {
let isCancelled = false;
fetch('/api/data')
.then(res => res.json())
.then(data => {
if (!isCancelled) setData(data);
});
return () => {
isCancelled = true;
};
}, []);
Explanation:
React lets you set class names using variables. You can use a ternary (? :) or helper libraries like classnames to change styles based on conditions.
const isActive = true;
return <div className={isActive ? "active" : "inactive"}>Hello</div>;
Explanation:
Passing props down many levels is messy. Instead, use React Context or global state libraries (like Redux or Zustand) to make state available at any level.
Explanation:
Use Context API or state management libraries like Redux or Zustand.
const MyContext = createContext();
<MyContext.Provider value={value}>
<DeepChild />
</MyContext.Provider>
Explanation:
React error boundaries catch runtime errors in rendering. Use a library like react-error-boundary to do this in functional components.
Explanation:
Wrap children with ErrorBoundary using react-error-boundary package or class components.
<ErrorBoundary fallback={<div>Something went wrong</div>}>
<MyComponent />
</ErrorBoundary>
useImperativeHandle?Explanation:
Sometimes the parent needs to call a method inside the child (like focus). Use useImperativeHandle and forwardRef for that.
Explanation:
Use forwardRef and useImperativeHandle.
const Child = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
focusInput: () => inputRef.current.focus()
}));
const inputRef = useRef();
return <input ref={inputRef} />;
});
Explanation:
If a component takes a long time to render and its props don’t change, wrap it in React.memo() to skip re-rendering.
Explanation:
Wrap the entire component in React.memo.
const ExpensiveTree = React.memo(() => {
// expensive rendering logic
return <div>Heavy Component</div>;
});
Explanation:
Use useRef to detect if a click was outside a component. This is useful for dropdowns, modals, etc., to close them when clicking elsewhere.
Explanation:
Use useRef with mousedown or click event listener.
useEffect(() => {
const handleClickOutside = e => {
if (ref.current && !ref.current.contains(e.target)) close();
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);
Explanation:
Use Context or global state to toggle modal visibility from anywhere in the app without prop drilling.
Explanation:
Use React Context or global state to toggle modals.
const ModalContext = createContext();
function App() {
const [modalOpen, setModalOpen] = useState(false);
return (
<ModalContext.Provider value={{ modalOpen, setModalOpen }}>
<Layout />
</ModalContext.Provider>
);
}
Explanation:
When items are added or removed from a list, animations make the UI feel smoother. Use libraries like framer-motion or react-transition-group to animate list changes.
Explanation:
Use react-transition-group or framer-motion to animate entering/exiting items.
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>
{item.text}
</motion.div>
Explanation:
Move the state to the child component and wrap it with React.memo(). This way, the parent doesn’t re-render unnecessarily.
Explanation:
Lift the child component into a memoized wrapper.
const Child = React.memo(({ value }) => <div>{value}</div>);
Explanation:
Use .env files to store different config values for dev and prod. Prefix with REACT_APP_ to access using process.env.REACT_APP_*.
Explanation:
Use .env.development, .env.production, and access with process.env.REACT_APP_*.
console.log(process.env.REACT_APP_API_URL);
Explanation:
Use HTML5 drag events like onDragStart, onDrop, and onDragOver, or simplify with libraries like react-beautiful-dnd for complex UIs.
Explanation:
Use HTML5 drag and drop API or a library like react-beautiful-dnd.
function handleDrop(e) {
const id = e.dataTransfer.getData("text/plain");
// move logic
}
<div draggable onDragStart={e => e.dataTransfer.setData("text/plain", item.id)}>
{item.name}
</div>
<div onDrop={handleDrop} onDragOver={e => e.preventDefault()} />
Explanation:
You can use route loaders (in React Router v6.4+) or fetch data in a layout component before rendering the route.
Explanation:
Use react-router loader functions (v6.4+) or trigger data fetch in parent layout.
useEffect(() => {
fetchData().then(setData);
}, [routeId]);
Explanation:
Lift the state up to a common parent or use Context to share the form data between components. This way, updates in one place reflect everywhere.
Explanation:
Lift form state to a common parent or use Context.
const [form, setForm] = useState({ name: "", email: "" });
function updateField(field, value) {
setForm(prev => ({ ...prev, [field]: value }));
}
Explanation:
Use animation state like isPaused and update animation props conditionally. Libraries like framer-motion make this easy.
Explanation:
Use CSS classes or state-driven animation libraries like framer-motion.
<motion.div animate={{ rotate: isPaused ? 0 : 360 }} transition={{ repeat: Infinity }} />
Explanation:
Use the prop-types package in JavaScript or switch to TypeScript to define strict types for props. This helps catch bugs early.
Explanation:
Use prop-types package or TypeScript.
import PropTypes from 'prop-types';
Component.propTypes = {
name: PropTypes.string.isRequired,
};
Explanation:
Controlled means value is set via state and updated with onChange. Uncontrolled means DOM handles it. Use useRef for uncontrolled components.
Explanation:
Controlled: value managed by React. Uncontrolled: DOM manages input state.
// Controlled
<input value={value} onChange={e => setValue(e.target.value)} />
// Uncontrolled
<input ref={inputRef} defaultValue="test" />
Explanation:
Race conditions happen when multiple async requests overlap. Use an increasing counter or AbortController to cancel older requests.
Explanation:
Use AbortController or request timestamps to cancel stale responses.
let latest = 0;
const fetchWithRace = async (query) => {
const current = ++latest;
const res = await fetch(`/search?q=${query}`);
if (current === latest) setData(await res.json());
};
Explanation:
Sometimes you want to scroll to a section of the page (like on button click). Use window.scrollTo() or ref.scrollIntoView() to do it programmatically.
Explanation:
Use window.scrollTo() or ref.scrollIntoView().
const ref = useRef();
<button onClick={() => ref.current.scrollIntoView()}>Scroll</button>
Explanation:
In tests, wrap your component inside Context.Provider or pass mock props directly. This helps simulate real scenarios without relying on actual data.
Explanation:
Use React Testing Library and wrap component in providers.
render(
<MyContext.Provider value={mockValue}>
<MyComponent />
</MyContext.Provider>
);
Explanation:
XSS (cross-site scripting) happens when unsafe input is rendered as HTML. Always escape user content or sanitize it before rendering. Never use dangerouslySetInnerHTML unless absolutely necessary.
Explanation:
Sanitize inputs before rendering and avoid dangerouslySetInnerHTML.
const safeText = input.replace(/</g, "<").replace(/>/g, ">");
return <div>{safeText}</div>;