> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/yogendrarana/craftdotui/llms.txt
> Use this file to discover all available pages before exploring further.

# useMounted

> A hook that tracks whether a component is currently mounted to the DOM

# useMounted

The `useMounted` hook tracks whether a component is currently mounted to the DOM. It returns `false` initially and on unmount, and `true` when the component is mounted. This is useful for preventing state updates on unmounted components.

## Installation

```bash theme={null}
npm install @craft-ui/hooks
```

## Import

```tsx theme={null}
import { useMounted } from "@craft-ui/hooks";
```

## Usage

```tsx theme={null}
import { useMounted } from "@craft-ui/hooks";
import { useState, useEffect } from "react";

function DataFetcher() {
  const mounted = useMounted();
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch("/api/data")
      .then(res => res.json())
      .then(result => {
        // Only update state if component is still mounted
        if (mounted) {
          setData(result);
        }
      });
  }, [mounted]);

  return <div>{data ? JSON.stringify(data) : "Loading..."}</div>;
}
```

## Returns

<ResponseField name="mounted" type="boolean">
  A boolean value that is `false` initially and on unmount, and `true` when the component is mounted.
</ResponseField>

## Type Definition

```typescript theme={null}
function useMounted(): boolean;
```

## Examples

### Preventing Memory Leaks

```tsx theme={null}
import { useMounted } from "@craft-ui/hooks";
import { useState, useEffect } from "react";

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

  useEffect(() => {
    const fetchData = async () => {
      try {
        const response = await fetch("/api/data");
        const result = await response.json();
        
        if (mounted) {
          setData(result);
          setLoading(false);
        }
      } catch (error) {
        if (mounted) {
          console.error(error);
          setLoading(false);
        }
      }
    };

    fetchData();
  }, [mounted]);

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

### Delayed Actions

```tsx theme={null}
import { useMounted } from "@craft-ui/hooks";
import { useState, useEffect } from "react";

function NotificationBanner({ message, duration = 3000 }) {
  const mounted = useMounted();
  const [visible, setVisible] = useState(true);

  useEffect(() => {
    const timer = setTimeout(() => {
      if (mounted) {
        setVisible(false);
      }
    }, duration);

    return () => clearTimeout(timer);
  }, [mounted, duration]);

  if (!visible) return null;

  return (
    <div className="notification">
      {message}
    </div>
  );
}
```

### Animation Delays

```tsx theme={null}
import { useMounted } from "@craft-ui/hooks";
import { useState, useEffect } from "react";

function FadeInComponent({ children }) {
  const mounted = useMounted();
  const [show, setShow] = useState(false);

  useEffect(() => {
    if (mounted) {
      // Delay to trigger CSS transition
      const timer = setTimeout(() => setShow(true), 10);
      return () => clearTimeout(timer);
    }
  }, [mounted]);

  return (
    <div
      style={{
        opacity: show ? 1 : 0,
        transition: "opacity 0.3s ease-in",
      }}
    >
      {children}
    </div>
  );
}
```

### Conditional Event Listeners

```tsx theme={null}
import { useMounted } from "@craft-ui/hooks";
import { useState, useEffect } from "react";

function KeyboardListener() {
  const mounted = useMounted();
  const [key, setKey] = useState("");

  useEffect(() => {
    const handleKeyPress = (e: KeyboardEvent) => {
      if (mounted) {
        setKey(e.key);
      }
    };

    if (mounted) {
      window.addEventListener("keypress", handleKeyPress);
    }

    return () => {
      window.removeEventListener("keypress", handleKeyPress);
    };
  }, [mounted]);

  return <div>Last key pressed: {key}</div>;
}
```

### WebSocket Connection

```tsx theme={null}
import { useMounted } from "@craft-ui/hooks";
import { useState, useEffect } from "react";

function WebSocketComponent() {
  const mounted = useMounted();
  const [messages, setMessages] = useState<string[]>([]);

  useEffect(() => {
    const ws = new WebSocket("ws://localhost:8080");

    ws.onmessage = (event) => {
      if (mounted) {
        setMessages(prev => [...prev, event.data]);
      }
    };

    return () => {
      ws.close();
    };
  }, [mounted]);

  return (
    <ul>
      {messages.map((msg, i) => (
        <li key={i}>{msg}</li>
      ))}
    </ul>
  );
}
```

### Polling Data

```tsx theme={null}
import { useMounted } from "@craft-ui/hooks";
import { useState, useEffect } from "react";

function PollingComponent() {
  const mounted = useMounted();
  const [data, setData] = useState(null);

  useEffect(() => {
    const pollData = async () => {
      const response = await fetch("/api/status");
      const result = await response.json();
      
      if (mounted) {
        setData(result);
      }
    };

    if (mounted) {
      pollData();
      const interval = setInterval(pollData, 5000);
      
      return () => clearInterval(interval);
    }
  }, [mounted]);

  return <div>{data ? JSON.stringify(data) : "Loading..."}</div>;
}
```

### Form Submission

```tsx theme={null}
import { useMounted } from "@craft-ui/hooks";
import { useState } from "react";

function FormComponent() {
  const mounted = useMounted();
  const [submitting, setSubmitting] = useState(false);
  const [success, setSuccess] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setSubmitting(true);

    try {
      await fetch("/api/submit", { method: "POST" });
      
      if (mounted) {
        setSuccess(true);
        setSubmitting(false);
      }
    } catch (error) {
      if (mounted) {
        setSubmitting(false);
      }
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit" disabled={submitting}>
        {submitting ? "Submitting..." : "Submit"}
      </button>
      {success && <p>Success!</p>}
    </form>
  );
}
```

## Common Patterns

### Safe State Updates

Wrap state updates in mounted checks:

```tsx theme={null}
const mounted = useMounted();

useEffect(() => {
  fetchData().then(result => {
    if (mounted) {
      setState(result);
    }
  });
}, [mounted]);
```

### Cleanup Pattern

Use with cleanup functions:

```tsx theme={null}
const mounted = useMounted();

useEffect(() => {
  const subscription = subscribe(data => {
    if (mounted) {
      handleData(data);
    }
  });

  return () => subscription.unsubscribe();
}, [mounted]);
```

### Custom Async Hook

```tsx theme={null}
import { useMounted } from "@craft-ui/hooks";
import { useState, useEffect } from "react";

function useAsync<T>(asyncFn: () => Promise<T>) {
  const mounted = useMounted();
  const [state, setState] = useState<{
    loading: boolean;
    data: T | null;
    error: Error | null;
  }>({ loading: true, data: null, error: null });

  useEffect(() => {
    asyncFn()
      .then(data => {
        if (mounted) {
          setState({ loading: false, data, error: null });
        }
      })
      .catch(error => {
        if (mounted) {
          setState({ loading: false, data: null, error });
        }
      });
  }, [mounted]);

  return state;
}
```

## Use Cases

* Preventing state updates after component unmounts
* Avoiding "Can't perform a React state update on an unmounted component" warnings
* Safely handling async operations (fetch, setTimeout, setInterval)
* Managing WebSocket connections
* Controlling animations and transitions
* Conditional event listener attachment
* Polling and real-time data updates

## Notes

* The hook returns `false` on initial render and after unmount
* The hook returns `true` after the component mounts (after `useEffect` runs)
* This pattern helps prevent memory leaks and React warnings
* Always check the `mounted` value before calling state setters in async callbacks
* The cleanup function automatically sets `mounted` to `false`
* This is particularly useful for components that fetch data or use timers
* Consider using AbortController for fetch requests as an alternative cancellation method
