Hone logo
Hone
Problems

React UseStack Hook: Managing a Stack Data Structure

This challenge asks you to create a custom React hook, useStack, that provides functionality for managing a stack data structure. A stack follows the Last-In, First-Out (LIFO) principle, and this hook will allow components to easily push, pop, peek, and check the size of a stack. This is useful for scenarios like undo/redo functionality, expression evaluation, or managing function call history.

Problem Description

You need to implement a useStack hook in TypeScript that provides the following functionalities:

  • Initialization: The hook should accept an initial value as an optional argument. This initial value will be the first element in the stack.
  • push(item: T): Adds an item to the top of the stack.
  • pop(): Removes and returns the item at the top of the stack. Returns undefined if the stack is empty.
  • peek(): Returns the item at the top of the stack without removing it. Returns undefined if the stack is empty.
  • size(): Returns the number of items in the stack.
  • isEmpty(): Returns true if the stack is empty, false otherwise.

The hook should manage the stack internally and return an object containing the functions described above. The type T represents the type of the items stored in the stack.

Key Requirements:

  • The hook must be written in TypeScript.
  • The hook must correctly implement the LIFO behavior of a stack.
  • The hook must handle edge cases such as an empty stack gracefully.
  • The hook should be efficient in terms of performance.

Expected Behavior:

The hook should maintain the stack's state and update it correctly with each operation. The returned functions should accurately reflect the current state of the stack.

Examples

Example 1:

Input: Initial value: [1, 2, 3]
Output:
  push(4) -> stack: [1, 2, 3, 4]
  peek() -> 4
  pop() -> 4, stack: [1, 2, 3]
  size() -> 3
  isEmpty() -> false

Explanation: The stack is initialized with [1, 2, 3]. Pushing 4 adds it to the top. Peeking returns the top element (4). Popping removes and returns 4. Size returns the current number of elements (3). isEmpty returns false.

Example 2:

Input: Initial value: []
Output:
  push("a") -> stack: ["a"]
  push("b") -> stack: ["a", "b"]
  pop() -> "b", stack: ["a"]
  peek() -> "a"
  size() -> 1
  isEmpty() -> false
  pop() -> "a", stack: []
  isEmpty() -> true
  pop() -> undefined, stack: []
  peek() -> undefined

Explanation: The stack starts empty. "a" and "b" are pushed. "b" is popped. "a" is peeked. The stack is then emptied, and subsequent pop and peek operations return undefined.

Example 3: (Edge Case - Empty Stack)

Input: Initial value: []
Output:
  pop() -> undefined
  peek() -> undefined
  size() -> 0
  isEmpty() -> true

Explanation: Demonstrates the behavior of the hook when initialized with an empty stack and attempting to pop or peek.

Constraints

  • The stack can hold any type of data (represented by the generic type T).
  • The push operation should be efficient (O(1) time complexity).
  • The pop, peek, size, and isEmpty operations should also be efficient (O(1) time complexity).
  • The hook should not cause unnecessary re-renders of the component using it.

Notes

  • Consider using a simple JavaScript array internally to represent the stack.
  • Remember to use the useState hook to manage the stack's state.
  • Think about how to handle the initial value correctly when initializing the stack.
  • Ensure your code is well-typed and handles potential errors gracefully.
  • Focus on creating a clean, reusable, and efficient hook.
Loading editor...
typescript