Hone logo
Hone
Problems

React Component Resumption Logic

This challenge focuses on implementing sophisticated logic within a React component to manage its state across unmount/remount cycles, often referred to as "resumption." This is crucial for applications where components might be temporarily hidden or removed from the DOM (e.g., in navigation, modal dismissals) but need to retain their internal state and resume gracefully when they reappear.

Problem Description

Your task is to create a React component that can gracefully resume its state when it's remounted after being unmounted. This means that if the component had a specific value in a state variable, or was in a particular UI state (like an expanded form or a list with specific scroll position), it should restore that state upon re-rendering.

Key Requirements:

  • State Persistence: The component must maintain and restore its internal state across unmount/remount cycles.
  • Resumption Hook: Implement a custom React hook (e.g., useResumableState) to abstract the state resumption logic. This hook should be reusable.
  • Conditional Rendering: The component should be mountable and unmountable dynamically (e.g., based on a parent component's state).
  • UI Feedback: Provide clear visual indicators of whether the component is in its initial state or a resumed state.

Expected Behavior:

  1. When the component mounts for the first time, its state should be initialized to a default or empty value.
  2. If the user interacts with the component and changes its state (e.g., types in an input field, toggles a setting), that state should be preserved.
  3. When the component is unmounted, its current state should be "saved" or persisted.
  4. When the component is remounted, it should retrieve the previously saved state and initialize its internal state with it.
  5. The component should clearly indicate if it has resumed from a previous state or if it's a fresh mount.

Edge Cases to Consider:

  • What happens if the component is remounted multiple times? The latest saved state should always be resumed.
  • How do you handle complex state objects or arrays? The hook should be able to handle various data types.
  • What if there's no saved state to resume from (e.g., the very first mount)?

Examples

Example 1: Text Input Resumption

Scenario: A simple text input field within a component.

// Parent Component (simplified)
function App() {
  const [showInput, setShowInput] = React.useState(false);
  const [message, setMessage] = React.useState(''); // State to control input visibility

  return (
    <div>
      <button onClick={() => setShowInput(!showInput)}>
        {showInput ? 'Hide Input' : 'Show Input'}
      </button>
      {showInput && <ResumableInput initialMessage="" onMessageChange={setMessage} />}
      <p>Current message from parent: {message}</p>
    </div>
  );
}

// ResumableInput Component
function ResumableInput({ initialMessage, onMessageChange }) {
  // ... implementation using the resumable hook
  return (
    <div>
      <label>Enter your text:</label>
      <input type="text" /* ... */ />
      <p>State Indicator: Initial / Resumed</p>
    </div>
  );
}

Initial State (First Mount):

  • The ResumableInput component mounts.
  • The input field is empty.
  • "State Indicator: Initial" is displayed.

User Interaction:

  • User types "Hello, Hone!" into the input field.
  • The internal state of ResumableInput is "Hello, Hone!".

Component Unmounts:

  • User clicks "Hide Input". The ResumableInput component is unmounted. Its state "Hello, Hone!" is persisted.

Component Remounts:

  • User clicks "Show Input" again. The ResumableInput component mounts.
  • The input field automatically shows "Hello, Hone!".
  • "State Indicator: Resumed" is displayed.
  • The onMessageChange prop (if implemented to update parent state) would also reflect "Hello, Hone!".

Example 2: Collapsible Section Resumption

Scenario: A section with a toggleable header that expands/collapses its content. The open/closed state should be remembered.

// Parent Component (simplified)
function App() {
  const [showSection, setShowSection] = React.useState(false);

  return (
    <div>
      <button onClick={() => setShowSection(!showSection)}>
        {showSection ? 'Hide Section' : 'Show Section'}
      </button>
      {showSection && <ResumableCollapsibleSection title="Advanced Settings" />}
    </div>
  );
}

// ResumableCollapsibleSection Component
function ResumableCollapsibleSection({ title }) {
  // ... implementation using the resumable hook
  return (
    <div>
      <h3>{title}</h3>
      {/* Content that is shown/hidden */}
      <p>State Indicator: Collapsed / Expanded</p>
    </div>
  );
}

Initial State (First Mount):

  • The ResumableCollapsibleSection mounts.
  • The content is initially collapsed.
  • "State Indicator: Collapsed" is displayed.

User Interaction:

  • User clicks the header or a toggle button.
  • The content expands. The internal state of ResumableCollapsibleSection is isExpanded: true.

Component Unmounts:

  • User clicks "Hide Section". The ResumableCollapsibleSection component is unmounted. Its state (isExpanded: true) is persisted.

Component Remounts:

  • User clicks "Show Section" again. The ResumableCollapsibleSection component mounts.
  • The content automatically appears expanded.
  • "State Indicator: Expanded" is displayed.

Constraints

  • State Management: The useResumableState hook should ideally abstract away the underlying mechanism for persisting state (e.g., sessionStorage, localStorage, or even an in-memory store managed by a higher-level context if persistence across sessions isn't required). For this challenge, let's assume sessionStorage is the preferred method for simplicity and session-based persistence.
  • Component Structure: The component using the resumption logic should be a functional component using React hooks.
  • Hook Design: The useResumableState hook should accept an initial state value and a unique key to identify the state in storage. It should return the current state value and a function to update it, similar to useState.
  • Performance: While not a strict performance bottleneck for typical UIs, avoid excessive re-renders or inefficient state comparisons.

Notes

  • Think about how to uniquely identify the state for each instance of a component if multiple instances of the same component type might exist. A key prop passed to the component or a unique identifier passed to the hook is essential.
  • Consider how to handle different data types for state. JSON.stringify and JSON.parse are your friends when using sessionStorage.
  • The "State Indicator" in the examples is crucial for visualizing and verifying the resumption logic.
  • This challenge is a stepping stone to building more robust and user-friendly React applications where state continuity is paramount.
Loading editor...
typescript