Hone logo
Hone
Problems

Implementing a usePromise Hook in React

The usePromise hook simplifies handling asynchronous operations within React components, particularly those involving Promises. This challenge asks you to implement this hook, which will accept a Promise and manage its loading, success, and error states, providing a clean and reusable way to consume asynchronous data. This is a common pattern in React applications and improves code readability and maintainability.

Problem Description

You are tasked with creating a custom React hook called usePromise. This hook will take a Promise as an argument and return an object containing information about the Promise's state: loading, data, and error. The hook should manage the lifecycle of the Promise, updating the state accordingly as the Promise resolves or rejects.

What needs to be achieved:

  • Create a React hook named usePromise that accepts a Promise as an argument.
  • The hook should track three states: loading, data, and error.
  • loading should be true while the Promise is pending.
  • data should hold the resolved value of the Promise when it resolves successfully.
  • error should hold the rejected reason of the Promise when it rejects.
  • The hook should return an object containing these three states: { loading, data, error }.

Key Requirements:

  • The hook must correctly handle Promise resolution and rejection.
  • The hook must update the state variables appropriately during the Promise lifecycle.
  • The hook should not cause unnecessary re-renders.
  • The hook should be reusable across different components and Promises.

Expected Behavior:

  1. When the usePromise hook is called with a Promise, loading should be set to true.
  2. If the Promise resolves successfully, loading should be set to false, data should be set to the resolved value, and error should be null or undefined.
  3. If the Promise rejects, loading should be set to false, data should be null or undefined, and error should be set to the rejection reason.
  4. Subsequent renders should reflect the current state of the Promise.

Edge Cases to Consider:

  • What happens if the Promise is already resolved or rejected when the hook is called?
  • What happens if the Promise never resolves or rejects (e.g., it's stuck in a pending state)?
  • How should the hook handle Promises that return undefined or null?
  • Consider the impact of multiple calls to usePromise with the same Promise.

Examples

Example 1:

Input: A Promise that resolves to "Data fetched successfully!" after 1 second.
Output:
{
  loading: false,
  data: "Data fetched successfully!",
  error: null
}
Explanation: After 1 second, the hook should update the state to reflect the resolved data.

Example 2:

Input: A Promise that rejects with an error message "Failed to fetch data" after 1 second.
Output:
{
  loading: false,
  data: null,
  error: "Failed to fetch data"
}
Explanation: After 1 second, the hook should update the state to reflect the rejection error.

Example 3:

Input: A Promise that immediately resolves to null.
Output:
{
  loading: false,
  data: null,
  error: null
}
Explanation: The hook should immediately update the state to reflect the resolved null value.

Constraints

  • The hook must be written in TypeScript.
  • The hook must be compatible with React 18 or later.
  • The hook should avoid unnecessary re-renders. Use useMemo or similar techniques if needed.
  • The Promise passed to the hook should be a standard JavaScript Promise.
  • The hook should not modify the original Promise.

Notes

  • Consider using the useEffect hook to manage the Promise lifecycle.
  • Think about how to handle potential race conditions if the Promise resolves or rejects very quickly.
  • The data and error states can be null or undefined when they are not in use.
  • Focus on creating a clean, reusable, and efficient hook. Test thoroughly with different Promise scenarios.
Loading editor...
typescript