react-simplikit

repository·main·Indexed 43 days ago

https://github.com/toss/react-simplikit

A collection of lightweight, zero-dependency React utilities providing hooks and components for state management, browser events, and mobile-specific web concerns such as keyboard handling and safe areas.

Tokens
65.7K
Snippets
220
Records
300
Agent score
52%

What's inside react-simplikit

  1. Overview of react-simplikit contents

    main

    The library provides three main categories of utilities:

    • Hooks: State and logic (e.g., useToggle, useDebounce, useList), browser events (e.g., useIntersectionObserver, useOutsideClickEffect), and mobile Web utilities (e.g., useAvoidKeyboard, useSafeAreaInset, useVisualViewport).
    • Components: UI components such as SwitchCase, Separated, and ImpressionArea.
    • Utility Functions: Core utilities like buildContext, mergeProps, and mergeRefs, as well as mobile Web helpers like isIOS and getKeyboardHeight.
  2. Overview of react-simplikit

    main

    react-simplikit is a lightweight library of React utility hooks, components, and utils designed to make application code simpler, safer, and more reliable.

    Key characteristics:

    • Declarative API: Provides interfaces that feel natural to React developers.
    • SSR Safe: Designed to minimize hydration mismatches and errors in Server-Side Rendering environments.
    • Zero Extra Dependencies: Has no dependencies beyond its peer dependencies on React and React-DOM.
    • No Hidden Logic: Implementations are concise and allow for external injection of logic/extensions to prevent unintended side effects.
  3. Overview of react-simplikit packages

    main

    The repository is organized into several packages:

    • react-simplikit: The main library containing React hooks, components, and utilities (state, logic, browser events, mobile web features).
    • react-simplikit-codemod: A codemod tool used to update your codebase when upgrading react-simplikit versions.
    • plugin: Agent skills for AI coding assistants.
  4. Overview of react-simplikit features

    main

    react-simplikit is a lightweight React utility library providing Hooks, Components, and Utilities.

    Core Modules:

    • Hooks: Includes state/logic hooks (useToggle, useDebounce, useList), browser event hooks (useIntersectionObserver, useOutsideClickEffect), and mobile web hooks (useAvoidKeyboard, useSafeAreaInset, useVisualViewport).
    • Components: UI components like SwitchCase, Separated, and ImpressionArea.
    • Utilities: Helper functions such as buildContext, mergeProps, mergeRefs, and mobile-specific utilities like isIOS and getKeyboardHeight.
  5. Choose a React utility by problem

    main

    Select a utility based on the specific behavior you need to implement. Common patterns include:

    • Show/hide content: Use useToggle for a boolean state and a toggle function.
    • Wait for typing to pause: Use useDebouncedValue to get a delayed copy of a state value (useful for filtering lists).
    • Delay a callback: Use useDebounce to get a function that schedules a callback with a .cancel() method.
    • Limit callback frequency: Use useThrottledCallback to limit how often a function executes.
    • Keep state across reloads: Use useStorageState to persist state in browser storage.
    • React to a click outside: Use useOutsideClickEffect for outside-click subscriptions.
    • Keep an input above the keyboard: Use useAvoidKeyboard to provide styles for positioning fixed elements.
    • Insert separators: Use the Separated component to add separators between children without a trailing separator.
    • Attach multiple refs: Use mergeRefs to combine multiple refs into a single ref callback.
  6. Store IDs instead of duplicating objects in state

    main

    When selecting an item from a list, do not copy the entire object into state. If the source object updates, your state will contain stale data. Instead, store only the id and derive the selected object from the original list during render.

    // ❌ const [selectedItem, setSelectedItem] = useState(items[0]);
    // ✅ const [selectedId, setSelectedId] = useState(items[0].id);
    //    const selectedItem = items.find(i => i.id === selectedId);
  7. Implement cleanup for async effects

    main

    Any effect performing asynchronous operations (like fetch, timers, or subscriptions) must include a cleanup function. This prevents race conditions where an older asynchronous response might overwrite a newer one if props or state change rapidly.

    useEffect(
      function fetchResults() {
        let ignore = false;
        fetchAPI(query).then(data => {
          if (!ignore) setResults(data);
        });
        return () => {
          ignore = true;
        };
      },
      [query]
    );
  8. Browser support and SSR for useNetworkStatus

    main

    Browser Support

    • Chrome/Edge (Android): Full support (all properties available).
    • Chrome/Edge (Desktop): Partial support (effectiveType, downlink, rtt, and saveData are available; type may be undefined).
    • Firefox: Not supported (all properties are undefined).
    • Safari: Not supported (all properties are undefined).

    SSR Safety

    useNetworkStatus is safe for Server-Side Rendering (SSR). On the server, it returns an empty object {} and only begins subscribing to network changes once running in the browser.

  9. Common react-simplikit use cases and hooks

    main

    Use the following mapping to identify which react-simplikit tool to use for common React development needs:

    State & Logic

    • Debouncing/Throttling: useDebounce, useDebouncedCallback, useThrottle, useThrottledCallback
    • Boolean State: useToggle (on/off/flip), useBooleanState (explicit set-true/set-false)
    • Numeric State: useCounter (with bounds/step)
    • Collection State: useList, useMap, useSet (with immutable helpers)
    • Persistence: useStorageState (localStorage/sessionStorage)
    • Timers: useInterval, useTimeout (declarative)
    • Callbacks & Refs: usePreservedCallback (stable identity), usePreservedReference (deep-equal skip), useRefEffect (tied to DOM ref), mergeRefs (combine multiple refs)
    • Effects: useAsyncEffect, useConditionalEffect (runs only when condition holds)
    • Input/Controlled: useControlledState, useInputState (onChange boilerplate)

    Browser Events & Interaction

    • User Interaction: useOutsideClickEffect (close menus/modals), useLongPress, useDoubleClick
    • Viewport/Visibility: useIntersectionObserver, useImpressionRef, ImpressionArea, useVisibilityEvent, usePageVisibility
    • Device/Browser: useGeolocation, useIsClient (SSR guard)

    Mobile Web Specifics

    • Keyboard: useAvoidKeyboard (fixed-bottom elements), useKeyboardHeight, isKeyboardVisible
    • Safe Area: useSafeAreaInset, getSafeAreaInset (notches/home-indicators)
    • Scroll: useBodyScrollLock (lock body scroll during modals/sheets)

    Components & Utilities

    • Rendering: SwitchCase (render by key), Separated (add separators between children)
    • Context: buildContext (boilerplate-free Context + Provider + hook)
    • Props: mergeProps (chain handlers, join classNames)
  10. Notify parents from event handlers instead of useEffect

    main

    When a child component needs to notify a parent about a state change, call the parent's callback directly within the same event handler that updates the child's state. Avoid using useEffect to watch for state changes and then call the parent callback, as this causes unnecessary cascading re-renders.

    // ❌ useEffect(() => { onChange(isOn); }, [isOn]);
    // ✅ function handleClick() { setIsOn(!isOn); onChange(!isOn); }
  11. Always return objects from hooks

    main

    To ensure extensibility and self-documenting code, always return an object { value } instead of a single value or a tuple. This allows adding new properties to the return value in the future without breaking existing implementations.

    // ✅ Recommended
    function useToggle(init: boolean): { value: boolean; toggle: () => void };
    
    // ❌ Avoid (Positional/Tuple)
    function useToggle(init: boolean): [boolean, () => void];
  12. Reset state using the key prop

    main

    To completely reset a component's state when a specific value changes (like a userId), use the key prop. Providing a new key forces React to treat the component as a brand new instance, performing a clean remount. This is preferred over using useEffect to manually clear state, which can cause stale values to be visible for one frame.

    // ❌ useEffect(() => { setComment(''); }, [userId]);
    // ✅ <Profile userId={userId} key={userId} />