context.tsx
Overview
context.tsx is a React context module that provides a centralized state management solution for controlling dropdown visibility within a React component tree. It defines a DropdownProvider component that encapsulates dropdown state logic and exposes a context with functions to manage which dropdown (if any) is currently active. The file ensures that only one dropdown can be active at a time, preventing UI conflicts by using a React context and hooks.
This file is designed to be used in scenarios where multiple dropdown components coexist, such as dropdown handles or draggable dropdowns, and there is a need to coordinate their open/closed states to avoid overlapping or conflicting dropdowns.
Detailed Explanation
Types and Interfaces
DropdownContextType
interface DropdownContextType {
canShowDropdown: () => boolean;
setActiveDropdown: (type: 'handle' | 'drag') => void;
clearActiveDropdown: () => void;
}
Defines the shape of the context value. It includes:
canShowDropdown: a function that returns a boolean indicating whether a dropdown can be shown (i.e., no other dropdown is currently active).setActiveDropdown: a function to mark a specific dropdown type ('handle'or'drag') as active.clearActiveDropdown: a function to clear the active dropdown state.
Context Creation
const DropdownContext = createContext<DropdownContextType | null>(null);
Creates a React context initialized with null. This context will hold the dropdown management functions and state.
Hook: useDropdownManager
export const useDropdownManager = () => {
const context = useContext(DropdownContext);
if (!context) {
throw new Error('useDropdownManager must be used within DropdownProvider');
}
return context;
};
A custom hook to consume the dropdown context. It throws an error if used outside the DropdownProvider, ensuring proper context usage.
Parameters: None
Returns: The current context object of type DropdownContextType.
Usage example:
const { canShowDropdown, setActiveDropdown, clearActiveDropdown } = useDropdownManager();
if (canShowDropdown()) {
setActiveDropdown('handle');
}
Component: DropdownProvider
interface DropdownProviderProps {
children: ReactNode;
}
export const DropdownProvider = ({ children }: DropdownProviderProps) => {
...
return (
<DropdownContext.Provider value={value}>
{children}
</DropdownContext.Provider>
);
};
This component provides the dropdown context to its descendant components.
Props:
children(ReactNode): React elements that will have access to the dropdown context.
Internal Implementation Details:
Uses a
useRefhook (activeDropdownRef) to store the currently active dropdown type, which can be'handle','drag', ornull.The ref is used instead of state to avoid unnecessary re-renders when the active dropdown changes.
Provides three methods, all wrapped in
useCallbackfor stable references:canShowDropdown: returnstrueif no dropdown is active.setActiveDropdown: sets the active dropdown type.clearActiveDropdown: clears the active dropdown state.
Usage example:
<DropdownProvider>
<YourComponent />
</DropdownProvider>
Inside YourComponent, you can use useDropdownManager to control dropdown visibility.
Important Implementation Details
Single Active Dropdown Management: The file enforces a constraint that only one dropdown can be active at a time. This is achieved through
activeDropdownRefwhich holds the currently active dropdown type.Ref vs State: Using
useReffor the active dropdown avoids re-rendering provider consumers unnecessarily, improving performance.Type Safety: The dropdown type is strictly limited to
'handle'or'drag'ensuring predictable usage.Context Safety: The hook
useDropdownManagerensures that the context is accessed only within the appropriate provider, preventing runtime errors.
Interaction with Other Parts of the System
This file is expected to be part of a UI component library or application where multiple dropdown components exist.
Components that render dropdowns (like handles or drag dropdowns) should be wrapped in
DropdownProviderat a higher level in the component tree.Dropdown components consume the context via
useDropdownManagerto:Check if they can show themselves (
canShowDropdown).Mark themselves as active (
setActiveDropdown).Clear their active status (
clearActiveDropdown).
This prevents multiple dropdowns from being open simultaneously, improving UX consistency.
Visual Diagram
classDiagram
class DropdownProvider {
-activeDropdownRef: Ref<'handle' | 'drag' | null>
+canShowDropdown(): boolean
+setActiveDropdown(type: 'handle' | 'drag'): void
+clearActiveDropdown(): void
+render()
}
class DropdownContext {
<<context>>
}
class useDropdownManager {
+(): DropdownContextType
}
DropdownProvider --> DropdownContext : provides
useDropdownManager ..> DropdownContext : consumes
Summary
context.tsx provides a clean and performant way to manage mutually exclusive dropdown visibility states in a React app. By wrapping components in DropdownProvider and using useDropdownManager, developers gain simple APIs to coordinate dropdown UI elements and ensure a smooth user experience without conflicting dropdowns.