Part 2 --- Performance Optimizations React is fast, but unnecessary… — Full Stack Camp — TG.ME

Part 2 --- Performance Optimizations

React is fast, but unnecessary re-renders can slow you down. Here’s how to stop them.

🔹 React.memo --- Component Caching

React.memo is a higher-order component. It prevents a component from re-rendering if its props haven't changed.
jsx
// Without memo: re-renders every time parent re-renders.
const ExpensiveComponent = ({ data }) => {
  console.log("Rendering!");
  return <div>{data}</div>;
};

// With memo: only re-renders if 'data' changes.
const MemoizedComponent = React.memo(ExpensiveComponent);

Warning: Memoization isn't free. Use it only for components that re-render often with the same props.

---

🔹 useCallback --- Memoizing Functions

When you pass a function as a prop, it gets re-created on every render. This breaks React.memo because the prop looks different every time.
jsx
// Bad: Creates a new function every render
function Parent() {
  const handleClick = () => console.log("clicked");
  return <Child onClick={handleClick} />;
}

// Good: useCallback caches the function
function Parent() {
  const handleClick = useCallback(() => {
    console.log("clicked");
  }, []); // Empty array = never changes
  return <Child onClick={handleClick} />;
}

Analogy: useCallback is like giving someone a permanent business card. Without it, you hand them a new one every time they see you (pointless).

---

🔹 useTransition --- Non-Urgent Updates

Sometimes state updates cause lag (e.g., filtering a giant list while typing). useTransition lets you mark certain updates as "low priority" so they don't block the UI.
jsx
import { useState, useTransition } from "react";

function SearchPage() {
  const [query, setQuery] = useState("");
  const [filteredList, setFilteredList] = useState([]);
  const [isPending, startTransition] = useTransition();

  const handleChange = (e) => {
    const value = e.target.value;
    setQuery(value); // Urgent update (typing)
   
    startTransition(() => {
      // Low priority update (filtering large array)
      const results = hugeList.filter(item => item.includes(value));
      setFilteredList(results);
    });
  };

  return (
    <div>
      <input value={query} onChange={handleChange} />
      {isPending && <p>Loading results...</p>}
    </div>
  );
}

---

Part 3 --- DOM & UI Mastery

🚪 Portals --- Rendering Outside the Parent

Sometimes you need to render something outside the root div (e.g., modals, tooltips, dropdowns) to avoid CSS clipping or z-index issues.

ReactDOM.createPortal lets you render a component anywhere in the DOM.
jsx
import { createPortal } from "react-dom";

function Modal({ children, isOpen }) {
  if (!isOpen) return null;
  // Render this modal inside the "modal-root" div instead of the parent tree
  return createPortal(
    <div className="modal-overlay">
      <div className="modal">{children}</div>
    </div>,
    document.getElementById("modal-root") // Must exist in index.html
  );
}

Analogy: Portals are like walkie-talkies. Even though you're in one room (parent component), you broadcast your message (modal UI) to another room (modal-root) seamlessly.

---

🪞 forwardRef & useImperativeHandle --- Advanced Refs

Sometimes you need to access a DOM element inside a child component. forwardRef lets the parent pass a ref down.
jsx
// Child component
const FancyInput = forwardRef((props, ref) => {
  return <input ref={ref} className="fancy" {...props} />;
});

// Parent component
function Parent() {
  const inputRef = useRef();
  useEffect(() => {
    inputRef.current.focus(); // Focusing the child's input
  }, []);
  return <FancyInput ref={inputRef} />;
}

useImperativeHandle lets you limit what the parent can do with the ref (like exposing only focus and clear).

const FancyInput = forwardRef((props, ref) => {
  const inputRef = useRef();
 
  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current.focus(),
    clear: () => { inputRef.current.value = ""; }
  }));

  return <input ref={inputRef} />;
});
July 5, 2026 66