import {
  SandpackProvider,
  SandpackLayout,
  SandpackCodeEditor,
} from "@codesandbox/sandpack-react";
import { Callout } from "nextra-theme-docs";

# Hooks

If you want to build a new component or you want to re-implement the code
editor, for example, you can still rely on the sandpack state and create your UI
from scratch.

The `sandpack-react` package exports a set of hooks, that give you access to the sandpack context in your own components.

## `useSandpack`

The main hook is called `useSandpack` and gives you the entire context object to play with.

<Callout>
Keep in mind that the `useSandpack` hook only works inside the `<SandpackProvider>`.
</Callout>

Let's build a code viewer component that renders a standard `pre` tag:

```jsx
import { useSandpack } from "@codesandbox/sandpack-react";

const SimpleCodeViewer = () => {
  const { sandpack } = useSandpack();
  const { files, activeFile } = sandpack;

  const code = files[activeFile].code;
  return <pre>{code}</pre>;
};
```

The `sandpack` object is available in any component and exposes all the internal
state:

- the `files` including all the setup/template files
- the `activeFile` / `visibleFiles` fields
- the `error` object, if any
- multiple functions for changing the state of sandpack: `updateCurrentFile`,
  `setActiveFile`, etc.

In the component above, you get the active code string by calling
`files[activeFile].code`, so any change of state will trigger a re-render of the
component and an update of the code.

We can test this with the `CustomSandpack` we implemented at the previous step.

```jsx
<SandpackProvider template="react">
  <SandpackLayout>
    <SandpackCodeEditor />
    {/* This will render the pre on the right side of your sandpack component */}
    <SimpleCodeViewer />
  </SandpackLayout>
</SandpackProvider>
```

If you run this, you will notice that the `SimpleCodeViewer` is in sync with the state of the `SandpackCodeEditor`.

`useSandpack` also exports `dispatch` and `listen`, you can levarage these functions for communicating directly with the bundler. However, at this point, you'd have
understood all the different types of messages and payloads that are passed from
the sandpack manager to the iframe and back.

```jsx
import { useSandpack } from "@codesandbox/sandpack-react";

const CustomRefreshButton = () => {
  const { dispatch, listen } = useSandpack();

  const handleRefresh = () => {
    // sends the refresh message to the bundler, should be logged by the listener
    dispatch({ type: "refresh" });
  };

  useEffect(() => {
    // listens for any message dispatched between sandpack and the bundler
    const stopListening = listen((msg) => console.log(msg));

    return () => {
      // unsubscribe
      stopListening();
    };
  }, [listen]);

  return (
    <button type="button" onClick={handleRefresh}>
      Refresh
    </button>
  );
};
```

Plus, `useSandpack` exposes a bunch of methods that you can use to manage the current state of the Sandpack instance:

| Method              | Description                                                    |
| ------------------- | -------------------------------------------------------------- |
| `closeFile`         | Close the given path in the editor                             |
| `deleteFile`        | Delete the given path in the editor                            |
| `dispatch`          | Sends a message to the bundler                                 |
| `listen`            | Listens for messages from the bundler                          |
| `openFile`          | Open the given path in the editor                              |
| `resetAllFiles`     | Reset all files for all paths to the original state            |
| `resetFile`         | Reset the code for a given path                                |
| `setActiveFile`     | Set a specific file as active in a given path                  |
| `updateFile`        | Update the content of a file in a given path or multiple files |
| `updateCurrentFile` | Update the content of the current file                         |

## `useSandpackNavigation`

Some of the common functionalities of sandpack are also extracted into
specialized hooks. These all use `useSandpack` under the hood, but abstract away
the shape of the **state** object and the **dispatch/listen** functions.

The refresh button can be built with the `useSandpackNavigation` hook:

```jsx
import { useSandpackNavigation } from "@codesandbox/sandpack-react";

const CustomRefreshButton = () => {
  const { refresh } = useSandpackNavigation();
  return (
    <button type="button" onClick={() => refresh()}>
      Refresh Sandpack
    </button>
  );
};
```

## `useActiveCode`

We implemented the `SandpackCodeEditor` on top of
[codemirror/next](https://codemirror.net/6/), but it is super easy to switch to
your favorite code editor. Let's connect the sandpack state to an instance of
[AceEditor](https://securingsincity.github.io/react-ace/). You can use the
`useActiveCode` hook, which gives you the `code` value and the `updateCode` callback.

```jsx
import { useActiveCode } from "@codesandbox/sandpack-react";
import AceEditor from "react-ace";
import "ace-builds/src-noconflict/mode-javascript";
import "ace-builds/src-noconflict/theme-textmate";

const CustomAceEditor = () => {
  const { code, updateCode } = useActiveCode();

  return (
    <AceEditor
      mode="javascript"
      defaultValue={code}
      onChange={updateCode}
      fontSize={14}
      height="300px"
      width="100%"
    />
  );
};
```

Now, let's put all of these custom components together:

```jsx
export const CustomSandpack = () => (
  <SandpackProvider template="react">
    <CustomAceEditor />
    <SandpackPreview showRefreshButton={false} showOpenInCodeSandbox={false} />
    <CustomRefreshButton />
    <CustomOpenInCSB />
  </SandpackProvider>
);
```

It's not pretty, but with just a few lines of code, you can create a whole new
component that uses the power of sandpack, but has all the UI and functionality
you need for your specific use case.

## `useSandpackConsole`

The [`SandpackConsole`](/advanced-usage/components#console) is implemented on top of this hook, which provides an interface to consume the logs from a specific sandpack client. Sandpack runs the console directly into the iframe. As a result, all console messages pass through the Sandpack protocol, where you can attach a listener to these messages in your own component or just use this hook.

```jsx
const { logs, reset } = useSandpackConsole();
```

## `useSandpackClient`

It registers a new sandpack client and returns its instance, listeners, and dispatch function. Using it when creating a custom component to interact directly with the client is recommended. For other cases, use `useSandpack` instead.

Example:

```jsx
const { iframe, listen } = useSandpackClient();

React.useEffect(() => {
  const unsubscribe = listen((message: SandpackMessage) => {
    if (message.type === "resize") {
      setComputedAutoHeight(message.height);
    }
  });

  return unsubscribe;
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

<iframe ref={ifram} />;
```

For more details, you can check the [SandpackPreview implementation](https://github.com/codesandbox/sandpack/blob/061ad9d596bcca437dbb04a1ee8306afd5bfd925/sandpack-react/src/components/Preview/index.tsx#L119).

## `useSandpackTheme`

It exposes the `theme` object configured on `SandpackContext` and contains an `id` to ensure uniqueness for custom themes. This `theme` object is responsible for distributing all the style configurations for the component thee.

## `useTranspiledCode`

It returns the transpile module from the bundler, the same one evaluated inside it.
