Hone logo
Hone
Problems

React Effect Tracking with Logging

Effect tracking is crucial for debugging and understanding the behavior of React components, especially when dealing with complex side effects. This challenge asks you to build a React hook that automatically logs the execution of effects, including their dependencies, making it easier to identify unexpected behavior and performance bottlenecks. This is particularly useful in larger applications where effects can become difficult to manage.

Problem Description

You need to create a custom React hook called useEffectTracker. This hook should wrap a standard useEffect hook and provide logging functionality to track when the effect runs, its dependencies, and any errors that occur within the effect. The hook should accept the same arguments as useEffect (effect callback, dependency array) and return the same as useEffect (cleanup function).

Key Requirements:

  • Logging: The hook must log to the console whenever the effect runs. The log message should include:
    • Component name (derived from the component's name if available, otherwise "Unknown Component")
    • Effect execution count (incrementing with each run)
    • Dependencies (displayed as a string)
  • Error Handling: The hook must catch any errors that occur within the effect callback and log them to the console, including the error message and stack trace. The error should not prevent the component from rendering.
  • Cleanup: The hook must correctly pass the cleanup function returned by the wrapped useEffect to the calling component.
  • Component Name Detection: Attempt to derive the component name from the calling component. If this is not possible (e.g., used outside a functional component), default to "Unknown Component".
  • Dependency String: Convert the dependency array to a readable string for logging purposes.

Expected Behavior:

  • The first time the effect runs, the log message should indicate the initial execution.
  • Subsequent runs of the effect should increment the execution count in the log message.
  • If an error occurs within the effect, it should be logged without crashing the component.
  • The cleanup function returned by useEffect should be correctly passed back to the component.

Edge Cases to Consider:

  • Empty dependency array: The effect should run only once on mount.
  • No dependency array: The effect should run on every render.
  • Effect callback that throws an error.
  • Cleanup function that throws an error.
  • Using the hook outside of a functional component (handle gracefully).

Examples

Example 1:

// Component: MyComponent
function MyComponent() {
  const [count, setCount] = useState(0);

  useEffectTracker(() => {
    console.log("Effect running with count:", count);
    // Simulate an error
    if (count > 5) {
      throw new Error("Count is too high!");
    }
  }, [count]);

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

Output (Console):

MyComponent: Effect execution 1, Dependencies: [count]
MyComponent: Effect execution 2, Dependencies: [count]
MyComponent: Effect execution 3, Dependencies: [count]
...
MyComponent: Effect execution 7, Dependencies: [count]
Error: Count is too high!
  at MyComponent (http://localhost:3000/main.js:12:15)
  at ...

Example 2:

function AnotherComponent() {
  const [data, setData] = useState<string | null>(null);

  useEffectTracker(() => {
    fetch('https://example.com/api/data')
      .then(response => response.json())
      .then(data => setData(JSON.stringify(data)))
      .catch(error => console.error("Error fetching data:", error));
  }, []);

  return (
    <div>
      <p>Data: {data || 'Loading...'}</p>
    </div>
  );
}

Output (Console):

AnotherComponent: Effect execution 1, Dependencies: []

Constraints

  • The hook must be written in TypeScript.
  • The logging should use console.log and console.error.
  • The hook should not introduce any unnecessary performance overhead. Avoid complex operations within the hook itself.
  • The component name detection should be as robust as possible, but a fallback to "Unknown Component" is acceptable.
  • The dependency array can contain any type of value.

Notes

  • Consider using a counter variable to track the number of effect executions.
  • The useDebugValue hook can be used to provide a more informative display of the hook's state in React DevTools. (Optional, but a nice-to-have).
  • Think about how to handle the component name gracefully when it's not readily available.
  • Focus on clear and concise code that is easy to understand and maintain.
  • This challenge is designed to test your understanding of useEffect, TypeScript, and React hooks.
Loading editor...
typescript