React Hooks: A Brief Summary

February 14, 2024

useState

useState is the most important react hook as it enables the core philosophy of react. The useState hook allows for a frontend that reacts to the variables stored in the application. The syntax is as follows:

const [variable, variableSetter] = useState(variableInit); // useState argument is the initial value of the variable

A component which contains a useState in its top level will re-render on every call of the variableSetter function, updating whatever parts of the DOM where the JSX had code that was dependent on the useState variable. One key thing to note is that mutation of a useState variable without call to the variable setter function will go unnoticed by react and will not cause a re-render. Because react keeps a virtual DOM that should reflect the real DOM, direct mutation might lead to bugs because the virtual DOM will not be consistent. useState only affects that state's value in the next render, not in the currently executed code.

useContext

The useContext hook is used to provide information to deeply nested components, and to pass props that would otherwise cause a prop-drill. The syntax is as follows :

const ThemeContext = createContext(initialValueOfContext); // creation of context

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  );
}
function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = "panel-" + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  );
}

useContext() always looks for the closest provider above the component that calls it. It searches upwards and does not consider providers in the component from which you’re calling useContext().

useEffect

The useEffect hook is used to synchronize a component with an external system. The first argument of useEffect is a callback that will run when a component mounts, and on every mutation of any variable in the array of dependencies (the second argument).

The function passed to the useEffect should do the setup code but also return a callback that cleans up anything that needs cleaning (clearing intervals, removing event listeners... )

useEffect(() => {
  const connection = createConnection(serverUrl, roomId);
  connection.connect();
  return () => {
    connection.disconnect();
  };
}, [serverUrl, roomId]);

useRef

The useRef is used to store information that is decoupled from the visual aspect of a component because changing a useRef value does not trigger a render and unlike other variables its value is not reset on every render.

const ref = useRef(initialValue);

the useRef function returns an object with the only property being current that can be mutated manually.

useRefs should be read or written to in a useEffect or in event handlers, but not in the components render.

UseCallback

this hook lets you cache a function definition between renders, it uses memoization to only change the callback if one of the dependencies change

const memoizedCallback = useCallback(() => {
  // callback logic
}, [dependencies]);

useCallback is especially useful when passing functions to child components, passing the same function prevents re rendering of children components thus improving optimize.

UseMemo

useMemo is similar to useCallback in the sense that they both are ways to memoize functions, the difference being that useMemo is especially useful for expensive computations, where react will save the result of a calculation and return it when the dependencies match.

const memoizedValue = useMemo(() => {
  // computation logic
  return result;
}, [dependencies]);

Notes

  • you may notice double initial render of components, especially when working with useEffect, that is only because of react strict mode that only applies to development mode to help you find accidental impurities