Hone logo
Hone
Problems

Custom UseState Hook with Initial Function

Creating custom hooks is a powerful way to encapsulate stateful logic and reuse it across your React components. This challenge asks you to build a custom useState hook that supports an optional initial function. This is particularly useful when the initial state is computationally expensive or depends on external factors, preventing unnecessary calculations on every render.

Problem Description

You need to implement a custom React hook called useCustomState. This hook should mimic the functionality of the built-in useState hook, but with the added capability of accepting an optional function as the initial state. If an initial function is provided, it should be called only once during the initial render to determine the initial state value. Subsequent renders should not re-execute the function.

Key Requirements:

  • State Management: The hook should manage a state variable and provide a way to update it.
  • Initial Function Support: If the first argument is a function, it should be called only once to initialize the state.
  • Updater Function: The second return value should be an updater function, similar to useState, that allows modifying the state. This function should accept either a new state value or a function that receives the previous state and returns the new state.
  • Re-renders: Calling the updater function should trigger a re-render of the component using the hook.
  • TypeScript: The code must be written in TypeScript.

Expected Behavior:

  • When the hook is first used, if an initial function is provided, it should be executed, and its return value should be used as the initial state.
  • Subsequent renders should not re-execute the initial function.
  • The updater function should allow setting the state to a new value or updating it based on the previous value.
  • Calling the updater function should trigger a re-render.

Edge Cases to Consider:

  • What happens if the initial function throws an error? (Consider handling this gracefully, perhaps by logging the error and using a default value).
  • How to ensure the initial function is only called once?
  • How to handle the updater function accepting both a new value and a function that updates the previous state.

Examples

Example 1:

Input: useCustomState(0)
Output: [0, (setState: (newState: number | ((prevState: number) => number)) => void)]
Explanation: The hook initializes the state to 0 and provides a function to update it.

Example 2:

Input: useCustomState(() => { return Math.random() * 100; })
Output: [someNumberBetween0And100, (setState: (newState: number | ((prevState: number) => number)) => void)]
Explanation: The hook initializes the state to a random number between 0 and 100. The function is only called once.

Example 3: (Edge Case)

Input: useCustomState(() => { throw new Error("Initialization failed!"); })
Output: [undefined, (setState: (newState: number | ((prevState: number) => number)) => void)]  // Or a default value, depending on error handling
Explanation: The initial function throws an error. The hook handles the error and initializes the state to undefined (or a default value).

Constraints

  • The hook must be written in TypeScript.
  • The initial function, if provided, should only be called once.
  • The updater function should accept either a new state value or a function that receives the previous state and returns the new state.
  • The hook should not introduce any unnecessary dependencies.
  • The hook should be compatible with standard React component usage.

Notes

  • Consider using useRef to track whether the initial function has already been executed.
  • Think about how to handle errors that might occur within the initial function.
  • The updater function should behave identically to the updater function provided by the built-in useState hook.
  • Focus on creating a clean, reusable, and well-documented hook.
Loading editor...
typescript