Hone logo
Hone
Problems

React useClipboard Hook Challenge

This challenge asks you to build a custom React hook called useClipboard. This hook will provide a convenient and reusable way to interact with the browser's clipboard API, allowing users to easily copy text to and from their clipboard within your React applications. Managing clipboard operations directly can often lead to repetitive code, so abstracting this functionality into a hook will improve code organization and maintainability.

Problem Description

You need to create a TypeScript React hook named useClipboard. This hook should manage the state and logic for copying text to the user's clipboard and potentially reading from it.

Key Requirements:

  1. copy function: The hook should expose a function (e.g., copy) that accepts a string and attempts to write it to the clipboard.
  2. isCopied state: The hook should return a boolean state variable (e.g., isCopied) that indicates whether the last copy operation was successful. This state should ideally reset automatically after a short period (e.g., 2 seconds) to provide visual feedback to the user.
  3. Error Handling: The hook should gracefully handle potential errors that might occur during clipboard operations (e.g., if the browser doesn't support the Clipboard API or if permissions are denied). It should return an error state or throw an error from the copy function.
  4. TypeScript: The hook and its return values/parameters must be strongly typed using TypeScript.

Expected Behavior:

  • When the copy function is called with a string:
    • It attempts to write the string to the clipboard.
    • If successful, isCopied should become true.
    • If unsuccessful (due to browser limitations, permissions, or other errors), an error should be handled, and isCopied should remain false.
    • After a short delay, isCopied should reset to false.
  • The hook should be usable across different React components.

Edge Cases to Consider:

  • Browsers that do not support the Clipboard API.
  • User explicitly denying clipboard permissions.
  • Calling copy with an empty string.
  • Calling copy multiple times in quick succession.

Examples

Example 1: Basic Copying

import React from 'react';
import useClipboard from './useClipboard'; // Assuming your hook is in './useClipboard.ts'

function MyComponent() {
  const { copy, isCopied, error } = useClipboard();
  const textToCopy = "Hello, world!";

  const handleClick = () => {
    copy(textToCopy);
  };

  return (
    <div>
      <button onClick={handleClick}>
        {isCopied ? 'Copied!' : 'Copy Text'}
      </button>
      {error && <p style={{ color: 'red' }}>Error: {error}</p>}
    </div>
  );
}

Output:

When the "Copy Text" button is clicked, "Hello, world!" is copied to the clipboard. The button text changes to "Copied!" for 2 seconds, then reverts to "Copy Text". If an error occurs, it's displayed below the button.

Example 2: Copying Dynamic Content

import React, { useState } from 'react';
import useClipboard from './useClipboard';

function DynamicCopyComponent() {
  const { copy, isCopied, error } = useClipboard();
  const [inputValue, setInputValue] = useState<string>('');

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="Enter text to copy"
      />
      <button onClick={() => copy(inputValue)} disabled={!inputValue}>
        {isCopied ? 'Copied!' : 'Copy Input'}
      </button>
      {error && <p style={{ color: 'red' }}>Error: {error}</p>}
    </div>
  );
}

Output:

The user can type text into the input field. When the "Copy Input" button is clicked, the current value of the input field is copied. The button text updates to "Copied!" temporarily. The button is disabled if the input field is empty.

Example 3: Error Handling (Conceptual)

If the browser doesn't support navigator.clipboard or if permissions are denied, the copy function would ideally either: a) Return false or undefined for isCopied and set an error string. b) Throw an actual Error object that the component can catch.

For this challenge, returning an error state is preferred.

// Inside the hook, if navigator.clipboard is undefined:
// const error = "Clipboard API not supported in this browser.";
// return { copy, isCopied, error };

Constraints

  • The hook must be implemented in TypeScript.
  • The copy function should be asynchronous, as clipboard operations can be asynchronous.
  • The isCopied state should reset automatically after approximately 2000 milliseconds (2 seconds).
  • Error messages, if any, should be informative strings.
  • The hook should ideally use the modern navigator.clipboard.writeText() API but should have a fallback or clear error message for unsupported environments.

Notes

  • Consider using navigator.clipboard.writeText() as it's the modern and recommended way to handle text copying.
  • Remember that navigator.clipboard might not be available in all environments (e.g., older browsers, some iframe contexts).
  • For isCopied reset, setTimeout is your friend.
  • Think about how you will manage the cleanup of the setTimeout when the component unmounts to prevent memory leaks. useEffect's cleanup function is crucial here.
  • You'll likely need to handle the case where navigator.clipboard or navigator.clipboard.writeText is undefined.
Loading editor...
typescript