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

lifecycle-management.mddocs/

Lifecycle Management

Hooks for handling component lifecycle events with proper cleanup and timing control.

Capabilities

useMount

Hook which asynchronously executes a callback once the component has been mounted. The callback is executed during the effect phase, not during render.

/**
 * Hook which asynchronously executes a callback once the component has been mounted.
 * @param callback - Function to call after mount.
 */
function useMount(callback: () => void): void;

Usage Examples:

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

function DataLoadingComponent() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useMount(() => {
    // Fetch data when component mounts
    fetchUserData()
      .then(setData)
      .finally(() => setLoading(false));
  });

  if (loading) return <div>Loading...</div>;
  return <div>Data: {JSON.stringify(data)}</div>;
}

// Focus management on mount
function AutoFocusInput() {
  const inputRef = useRef<HTMLInputElement>(null);

  useMount(() => {
    inputRef.current?.focus();
  });

  return <input ref={inputRef} placeholder="Auto-focused on mount" />;
}

// Analytics tracking
function AnalyticsComponent({ pageId }) {
  useMount(() => {
    // Track page view when component mounts
    analytics.track('page_view', { pageId });
  });

  return <div>Page content...</div>;
}

useUnmount

Hook which synchronously executes a callback when the component is about to unmount. Perfect for cleanup operations.

/**
 * Hook which synchronously executes a callback when the component is about to unmount.
 * @param callback - Function to call during unmount.
 */
function useUnmount(callback: () => void): void;

Usage Examples:

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

function WebSocketComponent() {
  const [socket, setSocket] = useState(null);

  useEffect(() => {
    const ws = new WebSocket('ws://localhost:8080');
    setSocket(ws);
  }, []);

  useUnmount(() => {
    // Clean up WebSocket connection
    if (socket) {
      socket.close();
    }
  });

  return <div>WebSocket component</div>;
}

// Event listener cleanup
function GlobalEventComponent() {
  const handleKeyPress = (event) => {
    console.log('Key pressed:', event.key);
  };

  useEffect(() => {
    document.addEventListener('keypress', handleKeyPress);
  }, []);

  useUnmount(() => {
    // Remove event listener on unmount
    document.removeEventListener('keypress', handleKeyPress);
  });

  return <div>Press any key</div>;
}

// Analytics cleanup
function TrackingComponent({ userId }) {
  useUnmount(() => {
    // Send final analytics event before unmount
    analytics.track('component_unmount', { userId });
  });

  return <div>Tracked component</div>;
}

useMountSync (Deprecated)

/**
 * Hook which synchronously executes a callback once the component has been mounted.
 * 
 * WARNING: This should only be used if you need to perform an action after the component has been 
 * mounted and before the browser paints. useMountSync will trigger debug warnings in server-rendered 
 * scenarios and should be used sparingly.
 * 
 * @deprecated Consider to use React.useEffect() or React.useLayoutEffect() directly based on use case
 * @param callback - Function to call once the component has been mounted.
 */
function useMountSync(callback: () => void): void;

Migration Guide:

// ❌ Deprecated useMountSync
useMountSync(() => {
  // Synchronous mount logic
});

// ✅ Use useLayoutEffect for synchronous DOM mutations
useLayoutEffect(() => {
  // Synchronous DOM updates before browser paint
}, []);

// ✅ Use useEffect for most mount logic
useEffect(() => {
  // Asynchronous mount logic
}, []);

// ✅ Use useMount for simple mount callbacks
useMount(() => {
  // Simple mount callback
});

useForceUpdate

Hook to force update a function component by updating a dummy state. Useful for cases where you need to trigger a re-render programmatically.

/**
 * Hook to force update a function component by updating a dummy state.
 * @returns Function that triggers a re-render when called
 */
function useForceUpdate(): () => void;

Usage Examples:

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

function ForceUpdateComponent() {
  const forceUpdate = useForceUpdate();
  const renderCount = useRef(0);
  
  renderCount.current += 1;

  return (
    <div>
      <div>Render count: {renderCount.current}</div>
      <button onClick={forceUpdate}>Force Re-render</button>
    </div>
  );
}

// Use case: External data that doesn't trigger re-renders
function ExternalDataComponent() {
  const forceUpdate = useForceUpdate();
  
  // External data store that doesn't trigger React updates
  const data = ExternalStore.getData();

  useEffect(() => {
    // Subscribe to external store
    const unsubscribe = ExternalStore.subscribe(() => {
      forceUpdate(); // Force re-render when external data changes
    });

    return unsubscribe;
  }, [forceUpdate]);

  return <div>External data: {data}</div>;
}

usePrevious

Hook keeping track of a given value from a previous execution of the component. Useful for comparing current and previous values.

/**
 * Hook keeping track of a given value from a previous execution of the component the Hook is used in.
 * @param value - The value to track
 * @returns The previous value, or undefined on first render
 */
function usePrevious<T>(value: T): T | undefined;

Usage Examples:

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

function ComparisonComponent({ count }: { count: number }) {
  const previousCount = usePrevious(count);

  return (
    <div>
      <div>Current count: {count}</div>
      <div>Previous count: {previousCount ?? 'None'}</div>
      {previousCount !== undefined && (
        <div>
          Count {count > previousCount ? 'increased' : 'decreased'} by {Math.abs(count - previousCount)}
        </div>
      )}
    </div>
  );
}

// Detecting prop changes
function PropChangeDetector({ userId, userName }) {
  const previousUserId = usePrevious(userId);
  const previousUserName = usePrevious(userName);

  useEffect(() => {
    if (previousUserId !== undefined && previousUserId !== userId) {
      console.log('User ID changed from', previousUserId, 'to', userId);
      // Perform cleanup or data refetch
    }
  }, [userId, previousUserId]);

  useEffect(() => {
    if (previousUserName !== undefined && previousUserName !== userName) {
      console.log('User name changed from', previousUserName, 'to', userName);
    }
  }, [userName, previousUserName]);

  return <div>User: {userName} (ID: {userId})</div>;
}

// Animation triggers
function AnimationComponent({ isVisible }) {
  const wasVisible = usePrevious(isVisible);
  const [animationClass, setAnimationClass] = useState('');

  useEffect(() => {
    if (wasVisible !== undefined) {
      if (!wasVisible && isVisible) {
        setAnimationClass('fade-in');
      } else if (wasVisible && !isVisible) {
        setAnimationClass('fade-out');
      }
    }
  }, [isVisible, wasVisible]);

  return (
    <div className={`content ${animationClass}`}>
      Content visibility: {isVisible ? 'visible' : 'hidden'}
    </div>
  );
}