Implement a useStack Custom Hook for Managing Stack Data in React
This challenge asks you to create a custom React hook called useStack that provides a simple and intuitive way to manage a stack data structure within your React components. A stack is a Last-In, First-Out (LIFO) data structure, and a hook for it can be incredibly useful for scenarios like managing undo/redo functionality, navigation history, or temporary state.
Problem Description
You need to implement a custom React hook useStack that returns an object with methods to interact with a stack. The hook should:
- Initialize: Accept an optional initial array of items to populate the stack.
- Provide State: Expose the current state of the stack (an array of items).
- Offer Core Operations:
push(item): Adds an item to the top of the stack.pop(): Removes and returns the item from the top of the stack. If the stack is empty, it should returnundefined.peek(): Returns the item at the top of the stack without removing it. If the stack is empty, it should returnundefined.isEmpty(): Returns a boolean indicating whether the stack is empty.clear(): Removes all items from the stack.
- Handle Updates: Ensure that when the stack state changes (via
push,pop, orclear), components using the hook re-render to reflect the updated stack.
Examples
Example 1:
import React from 'react';
import { useStack } from './useStack'; // Assuming your hook is in './useStack.ts'
function StackComponent() {
const { stack, push, pop, peek, isEmpty } = useStack<number>([1, 2]);
return (
<div>
<p>Stack: {JSON.stringify(stack)}</p>
<button onClick={() => push(3)}>Push 3</button>
<button onClick={() => pop()}>Pop</button>
<button onClick={() => alert(`Top item: ${peek()}`)}>Peek</button>
<p>Is Empty: {isEmpty() ? 'Yes' : 'No'}</p>
</div>
);
}
// Initial Render:
// Stack: [1,2]
// Is Empty: No
// After clicking "Push 3":
// Stack: [1,2,3]
// Is Empty: No
// After clicking "Pop":
// Stack: [1,2]
// Is Empty: No
// After clicking "Peek": (Alert shows "Top item: 3")
Example 2:
import React from 'react';
import { useStack } from './useStack';
function EmptyStackComponent() {
const { stack, push, pop, isEmpty, clear } = useStack<string>();
return (
<div>
<p>Stack: {JSON.stringify(stack)}</p>
<button onClick={() => push('hello')}>Push "hello"</button>
<button onClick={() => pop()}>Pop</button>
<button onClick={() => clear()}>Clear</button>
<p>Is Empty: {isEmpty() ? 'Yes' : 'No'}</p>
</div>
);
}
// Initial Render:
// Stack: []
// Is Empty: Yes
// After clicking "Push 'hello'":
// Stack: ["hello"]
// Is Empty: No
// After clicking "Pop":
// Stack: []
// Is Empty: Yes
// After clicking "Clear" on a non-empty stack:
// Stack: []
// Is Empty: Yes
Example 3: Popping from an empty stack
import React from 'react';
import { useStack } from './useStack';
function EmptyPopComponent() {
const { stack, pop, peek } = useStack<number>();
return (
<div>
<p>Stack: {JSON.stringify(stack)}</p>
<button onClick={() => alert(`Popped: ${pop()}`)}>Pop</button>
<button onClick={() => alert(`Peeked: ${peek()}`)}>Peek</button>
</div>
);
}
// Initial Render:
// Stack: []
// After clicking "Pop": (Alert shows "Popped: undefined")
// Stack: []
// After clicking "Peek": (Alert shows "Peeked: undefined")
// Stack: []
Constraints
- The hook must be implemented using TypeScript.
- The hook should use React's
useStatehook internally to manage the stack's state. - The provided methods (
push,pop,peek,isEmpty,clear) should be pure functions where possible, butpopandclearwill necessarily update state. - The hook should be generic, allowing it to manage stacks of any data type.
Notes
- Consider how you will handle state updates to ensure React re-renders correctly.
- Think about the return type of your hook and what information a component using it will need.
- The
popandpeekoperations should correctly returnundefinedwhen the stack is empty, as this is standard behavior for stack implementations.