Skip to content

@msflib/react-shared

Shared React utilities for all msflib modules. Provides common hooks and helpers that are used consistently across react-auth, react-notification, react-profile, and other modules.


Table of Contents


Installation

pnpm add @msflib/react-shared

Peer Dependencies

Package Version
react >= 18
@tanstack/react-query >= 5

API Reference

useActiveWorkspace

A React hook that returns the currently active workspace slug, and automatically triggers a re-render whenever the workspace changes via setActiveWorkspace() from @msflib/core.

useActiveWorkspace(): string | null

Returns:

  • string — the active workspace slug (e.g. 'acme-corp', 'globex')
  • null — when no workspace is active (single-workspace mode)

Usage:

import { useActiveWorkspace } from '@msflib/react-shared';

function WorkspaceBadge() {
  const workspace = useActiveWorkspace();

  if (!workspace) return null;

  return <span>Workspace: {workspace}</span>;
}

Usage in module providers (query key scoping):

Workspace-first query keys ensure React Query caches data separately per workspace and automatically refetches when the workspace switches.

import { useActiveWorkspace } from '@msflib/react-shared';
import { useQuery } from '@tanstack/react-query';

const NO_WORKSPACE = '__no_workspace__';

function NotificationProvider({ children }: { children: React.ReactNode }) {
  const workspace = useActiveWorkspace();

  const { data } = useQuery({
    // Workspace is first in the key so all workspace's data is partitioned separately.
    // When workspace changes, RQ sees a new key and auto-refetches — no extra code needed.
    queryKey: [workspace ?? NO_WORKSPACE, 'react-notification', 'list'],
    queryFn: () => api.list(),
  });

  return <>{children}</>;
}

How it works: The hook uses React 18's useSyncExternalStore to subscribe to subscribeActiveWorkspace from @msflib/core. When setActiveWorkspace() is called anywhere in the app, all components using useActiveWorkspace re-render synchronously with the new value — no React context or prop drilling needed.


createCallbackHandler

A utility that normalises TanStack Query mutation callback options to ensure onSuccess, onError, and onSettled are always safely forwarded — even when options is undefined.

createCallbackHandler<TData, TError, TVariables, TContext>(
  options?: MutateOptions<TData, TError, TVariables, TContext>
): MutateOptions<TData, TError, TVariables, TContext>

Usage in module providers:

import { createCallbackHandler } from '@msflib/react-shared';
import type { MutateOptions } from '@msflib/react-shared';

// Inside a module provider
const removeNotification = (
  id: number,
  options?: MutateOptions<void, Error, number>,
) => deleteMutation.mutate(id, createCallbackHandler(options));

Usage in your app:

import { useNotification } from '@msflib/react-notification';

function NotificationItem({ id }: { id: number }) {
  const { removeNotification } = useNotification();

  function handleDelete() {
    removeNotification(id, {
      onSuccess: () => toast('Notification removed'),
      onError: (err) => toast.error(err.message),
    });
  }

  return <button onClick={handleDelete}>Delete</button>;
}

Without createCallbackHandler, calling .mutate(vars, undefined) inside a mutation handler can cause runtime errors in some TanStack Query versions. This utility makes the pattern safe and consistent across all modules.


MutateOptions

A re-export of MutateOptions from @tanstack/react-query. Provided here so module consumers don't need to install @tanstack/react-query separately just for type imports.

import type { MutateOptions } from '@msflib/react-shared';