Hone logo
Hone
Problems

React useSet Custom Hook Challenge

This challenge asks you to implement a custom React hook called useSet. This hook will provide a state management solution specifically for sets, offering efficient ways to add, remove, and check for the existence of elements within a set, all while maintaining React's declarative nature. This is useful for managing unique collections of data in your React applications.

Problem Description

Your task is to create a TypeScript custom React hook named useSet. This hook should manage a Set data structure.

Key Requirements:

  1. Initialization: The hook should accept an optional initial value, which can be an iterable (like an array) to populate the set upon initialization. If no initial value is provided, an empty set should be created.
  2. State Management: The hook must internally use React's useState to manage the Set object.
  3. Core Set Operations: The hook should return functions to perform the following fundamental set operations:
    • add(element: T): Adds an element to the set.
    • remove(element: T): Removes an element from the set.
    • has(element: T): Returns true if the element exists in the set, false otherwise.
    • clear(): Removes all elements from the set.
  4. Set Access: The hook should also return the current Set object itself, allowing components to directly iterate over it or use other standard Set methods if needed.
  5. Type Safety: The hook should be generic (<T>) to support sets of any data type, ensuring type safety.
  6. Immutability: All operations that modify the set should create a new Set instance internally to ensure React can detect changes and re-render components correctly.

Expected Behavior:

When an element is added or removed, the hook should trigger a re-render of any component using it. The has operation should return the correct boolean value based on the current state of the set. The clear operation should result in an empty set.

Edge Cases:

  • Adding an element that already exists should not change the set.
  • Removing an element that does not exist should not change the set.
  • Initializing with an empty iterable or undefined.

Examples

Example 1: Basic Usage

import React from 'react';
import { useSet } from './useSet'; // Assuming useSet is in this file

function MyComponent() {
  const { set, add, remove, has, clear } = useSet<string>(['apple', 'banana']);

  return (
    <div>
      <h2>Fruits</h2>
      <ul>
        {[...set].map((fruit) => (
          <li key={fruit}>{fruit}</li>
        ))}
      </ul>
      <button onClick={() => add('orange')}>Add Orange</button>
      <button onClick={() => remove('banana')}>Remove Banana</button>
      <p>Has Apple? {has('apple') ? 'Yes' : 'No'}</p>
      <p>Has Grape? {has('grape') ? 'Yes' : 'No'}</p>
      <button onClick={clear}>Clear All</button>
    </div>
  );
}

Input to hook: ['apple', 'banana']

Expected Output (initial state): set will contain {'apple', 'banana'}. has('apple') will return true. has('grape') will return false.

After clicking "Add Orange": set will contain {'apple', 'banana', 'orange'}.

After clicking "Remove Banana": set will contain {'apple', 'orange'}.

After clicking "Clear All": set will contain {} (an empty set).

Example 2: Initializing with no values

import React from 'react';
import { useSet } from './useSet';

function AnotherComponent() {
  const { set, add, has } = useSet<number>();

  return (
    <div>
      <p>Current Set: {JSON.stringify(Array.from(set))}</p>
      <button onClick={() => add(10)}>Add 10</button>
      <p>Has 10? {has(10) ? 'Yes' : 'No'}</p>
    </div>
  );
}

Input to hook: undefined (or no argument)

Expected Output (initial state): set will be an empty set {}. has(10) will return false.

After clicking "Add 10": set will contain {10}. has(10) will return true.

Constraints

  • The useSet hook must be implemented in TypeScript.
  • It should not rely on any external state management libraries.
  • All provided functions (add, remove, clear) must correctly update the internal state and trigger re-renders.
  • The set object returned should be the actual Set instance.

Notes

  • Remember that Set objects in JavaScript are mutable. To make React detect changes, you'll need to create a new Set instance whenever you modify the existing one.
  • Consider how you will update the state using useState. The setter function from useState expects the new state value.
  • Think about how to provide the add, remove, has, and clear functions without them being recreated on every render unnecessarily (you can use useCallback for this).
  • The generic type T should be applied correctly to all relevant parts of the hook.
Loading editor...
typescript