or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

development-tools.mdevent-handling.mdindex.mdlifecycle-management.mdreference-management.mdstate-management.mdtiming-utilities.mdutility-hooks.md
tile.json

state-management.mddocs/

State Management

Essential hooks for managing component state with stable references and optimized performance patterns.

Capabilities

useBoolean

Hook to store a boolean value and generate callbacks for setting the value to true or false. The identity of the callbacks will always stay the same, making it perfect for React.memo optimization.

/**
 * Hook to store a value and generate callbacks for setting the value to true or false.
 * The identity of the callbacks will always stay the same.
 * @param initialState - Initial boolean value
 * @returns Array with the current value and an object containing the updater callbacks
 */
function useBoolean(initialState: boolean): [boolean, IUseBooleanCallbacks];

interface IUseBooleanCallbacks {
  /** Set the value to true. Always has the same identity. */
  setTrue: () => void;
  /** Set the value to false. Always has the same identity. */
  setFalse: () => void;
  /** Toggle the value. Always has the same identity. */
  toggle: () => void;
}

Usage Examples:

import { useBoolean } from "@fluentui/react-hooks";

function ToggleComponent() {
  const [isVisible, { setTrue: show, setFalse: hide, toggle }] = useBoolean(false);

  return (
    <div>
      <button onClick={show}>Show</button>
      <button onClick={hide}>Hide</button>
      <button onClick={toggle}>Toggle</button>
      {isVisible && <div>This content is visible!</div>}
    </div>
  );
}

// Optimized with React.memo - callbacks won't cause re-renders
const OptimizedChild = React.memo(({ onToggle }: { onToggle: () => void }) => {
  return <button onClick={onToggle}>Toggle from child</button>;
});

function ParentComponent() {
  const [isActive, { toggle }] = useBoolean(false);
  
  return (
    <div>
      <OptimizedChild onToggle={toggle} />
      {isActive && <div>Active state</div>}
    </div>
  );
}

useConst

Hook to initialize and return a constant value. Unlike React.useMemo, this is guaranteed to always return the same value and only call the initializer function once. Similar to setting a private member in a class constructor.

/**
 * Hook to initialize and return a constant value. Unlike React.useMemo, this is guaranteed to
 * always return the same value (and if the initializer is a function, only call it once).
 * @param initialValue - Initial value, or function to get the initial value. Only the value/function 
 * passed in the first time this is called is respected.
 * @returns The value. The identity of this value will always be the same.
 */
function useConst<T>(initialValue: T | (() => T)): T;

Usage Examples:

import { useConst } from "@fluentui/react-hooks";

function ExpensiveComponent() {
  // Expensive object creation - only runs once
  const expensiveObject = useConst(() => ({
    data: performExpensiveCalculation(),
    cache: new Map(),
    timestamp: Date.now()
  }));

  // Simple constant value
  const componentId = useConst(() => `component-${Math.random()}`);

  // Function constant
  const stableCallback = useConst(() => () => {
    console.log("This callback never changes");
  });

  return (
    <div id={componentId}>
      <div>Expensive data: {expensiveObject.data}</div>
      <button onClick={stableCallback}>Stable callback</button>
    </div>
  );
}

useControllableValue

Hook to manage a value that could be either controlled or uncontrolled, such as a checked state or text box string. This pattern is essential for creating components that can work both in controlled and uncontrolled modes.

/**
 * Hook to manage a value that could be either controlled or uncontrolled
 * @param controlledValue - The controlled value passed in props. Always used if provided.
 * @param defaultUncontrolledValue - Initial value for internal state in uncontrolled case.
 * @returns Array of current value and updater callback with stable identity.
 */
function useControllableValue<TValue, TElement extends HTMLElement>(
  controlledValue: TValue | undefined,
  defaultUncontrolledValue: TValue | undefined
): Readonly<[TValue | undefined, (update: React.SetStateAction<TValue | undefined>) => void]>;

/**
 * Overload with onChange callback for event handling
 * @param controlledValue - The controlled value passed in props
 * @param defaultUncontrolledValue - Initial value for internal state
 * @param onChange - Callback fired when value changes
 * @returns Array of current value and updater callback that calls onChange
 */
function useControllableValue<
  TValue,
  TElement extends HTMLElement,
  TEvent extends React.SyntheticEvent<TElement> | undefined
>(
  controlledValue: TValue | undefined,
  defaultUncontrolledValue: TValue | undefined,
  onChange: ChangeCallback<TElement, TValue, TEvent> | undefined
): Readonly<[
  TValue | undefined, 
  (update: React.SetStateAction<TValue | undefined>, ev?: React.FormEvent<TElement>) => void
]>;

type ChangeCallback<
  TElement extends HTMLElement,
  TValue,
  TEvent extends React.SyntheticEvent<TElement> | undefined
> = (ev: TEvent, newValue: TValue | undefined) => void;

Usage Examples:

import { useControllableValue } from "@fluentui/react-hooks";

// Basic controllable input component
interface TextInputProps {
  value?: string;
  defaultValue?: string;
  onChange?: (event: React.ChangeEvent<HTMLInputElement>, newValue: string | undefined) => void;
}

function TextInput({ value, defaultValue, onChange }: TextInputProps) {
  const [currentValue, setValue] = useControllableValue(value, defaultValue, onChange);

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(event.target.value, event);
  };

  return (
    <input
      type="text"
      value={currentValue || ""}
      onChange={handleChange}
    />
  );
}

// Usage as controlled component
function ControlledExample() {
  const [text, setText] = useState("controlled");
  
  return (
    <TextInput
      value={text}
      onChange={(ev, newValue) => setText(newValue || "")}
    />
  );
}

// Usage as uncontrolled component
function UncontrolledExample() {
  return (
    <TextInput
      defaultValue="uncontrolled"
      onChange={(ev, newValue) => console.log("Changed to:", newValue)}
    />
  );
}

useConstCallback (Deprecated)

/**
 * @deprecated Deprecated due to potential for misuse. Generally, use React.useCallback instead.
 * If you need a callback reference that never changes, consider useEventCallback.
 * 
 * This hook was intended for creating callbacks which have no dependencies, and therefore never
 * need to change. Usage tends to result in bugs like unintentionally capturing the first value
 * of a prop and not respecting updates.
 */
function useConstCallback<T extends (...args: any[]) => any>(callback: T): T;

Migration Guide:

// ❌ Deprecated useConstCallback
const callback = useConstCallback(() => {
  // This captures the initial value and never updates
  console.log(someProp);
});

// ✅ Use useEventCallback instead
const callback = useEventCallback(() => {
  // This always uses the latest value
  console.log(someProp);
});

// ✅ Or use React.useCallback with proper dependencies
const callback = useCallback(() => {
  console.log(someProp);
}, [someProp]);