Unraveling the Mysteries of React’s Component Lifecycle

A New Era of Development

The introduction of Hooks in React 16.8 marked a significant shift in the way developers write components. By leveraging Hooks, developers can save time and avoid unnecessary code and boilerplate.

Understanding the Component Lifecycle

To truly master React, it’s essential to grasp the intricacies of the component lifecycle. React is reactive to changes in props and state, which can trigger re-renders. But what exactly happens when these changes occur?

The Basics of Props and State

Let’s start with the fundamentals. A prop is an external variable passed to a component, while a state is an internal variable that persists across multiple renders. Both props and state variables cause a re-render when they change. The only difference between a state and a ref is that a ref change does not cause a re-render.

const MyComponent = ({ prop }) => {
  const [state, setState] = useState(0);
  const ref = useRef(null);

  // prop change triggers re-render
  // state change triggers re-render
  // ref change does not trigger re-render
}

Re-Renders: The Unexpected Consequences

Consider a scenario where a parent component changes, triggering a re-render of its child components. You might expect that only the components with changed props or state would re-render. However, in practice, all child components will re-render, even if their props and state remain unchanged.

const Parent = () => {
  const [count, setCount] = useState(0);

  return (
    <div>
      <Child />
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

const Child = () => {
  // re-renders even though props and state remain unchanged
  return <p>Hello World!</p>;
}

The Power of Memoization

React provides a built-in function called memo that can prevent unnecessary re-renders by memoizing the result of the component. This technique should be used sparingly, as it can have unintended consequences.

import { memo } from 'eact';

const MyComponent = memo(() => {
  // memoized component
  return <p>Hello World!</p>;
});

Call Order: The Bottom-Up Approach

When it comes to useEffect Hooks, the call order is crucial. Effects are called in a bottom-up fashion, resolving first in the children and then in the parent. This means that the effects will run after the component is mounted, but before the DOM is updated.

const Parent = () => {
  useEffect(() => {
    // runs last
  }, []);

  return (
    <div>
      <Child />
    </div>
  );
};

const Child = () => {
  useEffect(() => {
    // runs first
  }, []);

  return <p>Hello World!</p>;
};

Callback Refs: A Word of Caution

Callback refs can have unexpected behavior, especially when the component is updated. They are called between components rendering and effects running, but can be executed twice, with the ref being null during the first execution.

const MyComponent = () => {
  const ref = useRef(null);

  useEffect(() => {
    // called twice, ref is null during first execution
    ref.current && doSomething();
  }, [ref]);

  return <div ref={ref}></div>;
};

Mastering the Component Lifecycle

React Hooks are powerful, but mastering the component lifecycle requires patience and practice. By understanding the intricacies of re-renders, memoization, and call order, you can optimize your application’s performance and avoid common pitfalls.

Leave a Reply