Hone logo
Hone
Problems

Custom React Hooks: UseCounter and UseLocalStorage

This challenge focuses on building custom React hooks to encapsulate common logic and improve code reusability. You'll implement useCounter for managing a counter with increment, decrement, and reset functionalities, and useLocalStorage for persisting a value in local storage. These hooks demonstrate how to abstract state management and side effects, making your components cleaner and more maintainable.

Problem Description

Your task is to create two custom React hooks: useCounter and useLocalStorage.

useCounter Hook:

This hook should manage a counter value and provide functions to interact with it. It should accept an initial value as an argument. The hook should return:

  • count: The current counter value (number).
  • increment: A function to increment the counter by 1.
  • decrement: A function to decrement the counter by 1.
  • reset: A function to reset the counter to its initial value.

useLocalStorage Hook:

This hook should persist a value in local storage. It should accept a key and an initial value as arguments. The hook should:

  • Retrieve the value from local storage using the provided key on initial render. If the key doesn't exist, use the initial value.
  • Store the value in local storage whenever it changes.
  • Return:
    • value: The current value (any type).
    • setValue: A function to update the value, which should also update local storage.

Key Requirements:

  • Both hooks must be written in TypeScript.
  • useLocalStorage must handle potential errors during local storage access gracefully (e.g., browser security settings preventing access). If an error occurs, use the initial value.
  • The useLocalStorage hook should only update local storage when the value actually changes.
  • The hooks should be reusable and independent of any specific component.

Expected Behavior:

  • useCounter should correctly increment, decrement, and reset the counter value.
  • useLocalStorage should correctly retrieve and persist values in local storage.
  • Changes to the value managed by useLocalStorage should be reflected in local storage.
  • The hooks should not cause unnecessary re-renders.

Examples

Example 1: useCounter

Input: Initial value = 0
Output:
- count: 0
- increment() increments count by 1
- decrement() decrements count by 1
- reset() sets count back to 0

Explanation: The hook initializes the counter to 0. Calling increment() increases the counter, decrement() decreases it, and reset() returns it to 0.

Example 2: useLocalStorage

Input: key = "myValue", initialValue = "hello"
Output:
- value: (If "myValue" exists in local storage, its value; otherwise, "hello")
- setValue(newValue): Updates the value and persists it in local storage under the key "myValue".

Explanation: The hook retrieves the value associated with "myValue" from local storage. If it doesn't exist, it uses "hello". setValue updates both the component's state and local storage.

Example 3: useLocalStorage - Error Handling

Input: key = "myValue", initialValue = 123, Local Storage is inaccessible (e.g., due to browser settings)
Output:
- value: 123
- setValue(newValue): Updates the value and attempts to persist it in local storage. If persistence fails, the value is still updated in the component's state, but not in local storage.

Explanation: Because local storage is inaccessible, the hook uses the initial value and continues to function, updating the component's state even if it can't persist to local storage.

Constraints

  • The useCounter hook should not have any performance constraints beyond standard React best practices.
  • The useLocalStorage hook should avoid unnecessary local storage writes. Only write to local storage when the value actually changes.
  • Both hooks must be implemented using functional components and React hooks.
  • The code must be valid TypeScript.

Notes

  • Consider using useState for managing the internal state within each hook.
  • For useLocalStorage, use localStorage.getItem() and localStorage.setItem() to interact with local storage.
  • Remember to handle potential errors when accessing local storage.
  • Think about how to prevent unnecessary re-renders when the value changes. Use memoization techniques if needed.
  • Focus on creating clean, reusable, and well-documented code.
  • The goal is to demonstrate your understanding of custom hooks and their benefits.
Loading editor...
typescript