Hone logo
Hone
Problems

Implementing a useWhyDidYouUpdate Hook in React

The useWhyDidYouUpdate hook, inspired by the popular Redux DevTools extension, helps developers understand why a React component is re-rendering. This challenge asks you to implement a custom hook that tracks previous props and state values and logs a message when the component re-renders, detailing the changes. This is invaluable for performance optimization and debugging unnecessary re-renders.

Problem Description

You need to implement a custom React hook called useWhyDidYouUpdate. This hook should accept a component name as an argument and track the previous values of the component's props and state. Whenever the component re-renders, the hook should compare the current props and state with the previously stored values. If any differences are detected, it should log a message to the console indicating the component name and the specific changes that occurred. If no changes are detected, no message should be logged.

Key Requirements:

  • Tracking: The hook must accurately track the previous props and state.
  • Comparison: It must correctly compare the current and previous values.
  • Logging: It must log informative messages to the console when re-renders occur due to prop or state changes.
  • Component Name: The hook must accept a component name as an argument for clear identification in the console logs.
  • TypeScript: The implementation must be in TypeScript.
  • No External Dependencies: The solution should not rely on any external libraries beyond React itself.

Expected Behavior:

  • On the initial render, the hook should store the initial props and state.
  • On subsequent renders, the hook should compare the current props and state with the stored previous values.
  • If any prop or state value has changed, the hook should log a message to the console in the following format: "Component [componentName] re-rendered: prop [propName] changed from [oldValue] to [newValue] | state [stateName] changed from [oldValue] to [newValue]". Multiple changes should be logged on a single line, separated by |.
  • If no props or state values have changed, the hook should do nothing.
  • The hook should return undefined.

Edge Cases to Consider:

  • Components that receive different props on each render.
  • Components that update their state frequently.
  • Components that use memo or shouldComponentUpdate to prevent re-renders. The hook should still function correctly in these scenarios.
  • Props and state that are objects or arrays. Deep comparison may be necessary for these types. (For simplicity, a shallow comparison is acceptable for this challenge).
  • Component unmounting. (While not strictly required, handling unmounting gracefully is good practice).

Examples

Example 1:

// Component: MyComponent
function MyComponent({ count, name }: { count: number; name: string }) {
  const [state, setState] = React.useState(0);

  useWhyDidYouUpdate("MyComponent");

  return (
    <div>
      Count: {count}, Name: {name}, State: {state}
      <button onClick={() => setState(state + 1)}>Increment State</button>
    </div>
  );
}

// Initial Render:
// Input: count = 1, name = "Alice", state = 0
// Output: (No output - initial render)

// Render after clicking "Increment State" once:
// Input: count = 1, name = "Alice", state = 1
// Output: "Component MyComponent re-rendered: state state changed from 0 to 1"

// Render after changing the count prop:
// Input: count = 2, name = "Alice", state = 1
// Output: "Component MyComponent re-rendered: prop count changed from 1 to 2"

Example 2:

// Component: AnotherComponent
function AnotherComponent({ data }: { data: { value: number } }) {
  useWhyDidYouUpdate("AnotherComponent");

  return <div>Value: {data.value}</div>;
}

// Initial Render:
// Input: data = { value: 10 }
// Output: (No output - initial render)

// Render after data.value changes:
// Input: data = { value: 20 }
// Output: "Component AnotherComponent re-rendered: prop data changed from {value: 10} to {value: 20}"

Constraints

  • The solution must be written in TypeScript.
  • The solution should not use any external libraries beyond React.
  • Shallow comparison of props and state is acceptable. Deep comparison is not required.
  • The hook should be performant enough to not significantly impact the component's rendering performance. Avoid unnecessary computations.

Notes

  • Consider using React.useEffect to track changes.
  • The useWhyDidYouUpdate hook should be reusable across different components.
  • Think about how to handle different data types for props and state.
  • Focus on clarity and readability in your code. Good comments are appreciated.
  • The component name is a string and should be used for identification purposes in the console logs.
  • The hook should not prevent the component from re-rendering. It should only log information about the re-render.
Loading editor...
typescript