> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/get-started/faq/react-global-instance.md).

# Sharing WebViewer instance across components

World's #1 PDF SDK Library for Web, Mobile, Server, Desktop

## The problem

Webviewer can easily be instantiated inside a React component, however, the `instance` object returned from the WebViewer constructor is limited to the scope of the component its created in:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
import {useEffect, useRef} from 'react';
import WebViewer from '@pdftron/webviewer'

const MyComponent = () => {
  const viewer = useRef(null);

  useEffect(() => {
    WebViewer(
      {
        path: '/webviewer/lib',
        initialDoc: 'https://pdftron.s3.amazonaws.com/downloads/pl/demo-annotated.pdf',
      },
      viewer.current,
    ).then((instance) => {
         // We only have access to the instance here
      });
  }, []);

  return (
    <div className="MyComponent">
      <div className="webviewer" ref={viewer} style={{height: "100vh"}}></div>
    </div>
  );
};
```

{% endcode %}
{% endtab %}
{% endtabs %}

In most React apps, you want to separate functionality on a per-component basis. For example, you may want a React component that loads a new document.

One way you could do this is by passing `instance` down as a prop to all of your components - but this can get messy and leads to prop drilling. Prop drilling occurs when you pass a prop down through multiple child components, and this pattern should be avoided because it leads to messy, hard to maintain code.

## React context

To avoid prop drilling, we can use a powerful feature in React called [context](https://reactjs.org/docs/context.html).

Context allows you to share data between components without the use of props. This is a great feature that can really clean up your code.

Let's use the context feature to share our WebViewer instance object with all of our components.

### Creating the context

The first thing we need to do is create the context itself. This can be done with the `createContext` function. This context can live anywhere in your app, but for this example lets place it in `src/context/webviewer.js`

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// src/context/webviewer.js 

import React from 'react'

export default WebViewerContext = React.createContext({});
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Setting up the provider

Next, we need to *provide* our application with this context. You may be familiar with this concept if you have ever used libraries like Apollo, Redux, Chakra, etc.

To set up our provider, we simply wrap our entire app with the provider exported from our context:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// src/App.js

import WebViewerContext from 'src/context/webviewer.js '

export default function App() {
  return (
    <WebViewerContext.Provider>
      { /* ...Your application code here */}
    </WebViewerContext.Provider>
  )
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

Now, any components rendered inside this provider have access to the context.

We also have to provide some kind of value to our application. This value can be whatever you want, but for this example we will provide a way to get and set the WebViewer instance.

Expanding on our previous code, we provide set a getter and setter for the instance using the `useState` hook:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// src/App.js

import WebViewerContext from 'src/context/webviewer.js'
import { useState } from 'react'

export default function App() {

  const [instance, setInstance] = useState();

  return (
    <WebViewerContext.Provider value={{ instance, setInstance }}>
      { /* ...Your application code here */}
    </WebViewerContext.Provider>
  )
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

Now, every component in our app has access to both `instance` and `setInstance`.

### Accessing and setting the context

The next step is setting the WebViewer instance object after WebViewer has been loaded. To do this, we need to call the `setInstance` function provided by our provider.

In our WebViewer component, we can gain access to this function with the `useContext` hook:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// src/components/WebViewer.js

import WebViewerContext from 'src/context/webviewer.js'
import { useEffect, useRef, useContext } from 'react';
import WebViewer from '@pdftron/webviewer'

export default function WebViewerComponent() {

  // useContext returns whatever "value" 
  // is provided by our provider we set up above
  const { setInstance } = useContext(WebViewerContext);

  const viewer = useRef(null);

  useEffect(() => {
    WebViewer(
      {
        path: '/webviewer/lib',
        initialDoc: '/files/pdftron_about.pdf',
      },
      viewer.current,
    ).then((instance) => {
      setInstance(instance) 
    });
  }, []);

  return (
    <div className="MyComponent">
      <div className="webviewer" ref={viewer} style={{height: "100vh"}}></div>
    </div>
  );
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

This code is loading WebViewer and mounting it to the DOM, and then calling the `setInstance` function provided from our provider. If everything is set up correctly, the `instance` state in `App.js` should now be set to the WebViewer instance, which means that our provider is now providing the WebViewer instance object to the rest of the application!

### Using the instance

Now that the instance is set in our provider, every component now has access to it. This allows us to call WebViewer APIs without passing any props.

Let's create a `LoadDocument` component now using our new context:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// src/components/LoadDocument.js

import WebViewerContext from 'src/context/webviewer.js'
import { useEffect, useRef, useContext } from 'react';

export default function LoadDocument() {

   const { instance } = useContext(WebViewerContext)

   const load = () => {
      instance.UI.loadDocument('http://yourwebsite.com/file.pdf')
   }

   return (
     <button onClick={load}>Load document</button>
   )
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

You can see that this component now has access to the WebViewer instance with no props needed!

### Cleaning up

We can clean up our code even further by creating a custom hook that just returns the instance. This prevents us from having to import the context everywhere we want to use it.

Let's create a custom hook called `useInstance`:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// src/hooks/useInstance

import WebViewerContext from 'src/context/webviewer.js'
import { useContext } from 'react';

export default function useInstance() {
  const { instance } = useContext(WebViewerContext);
  return instance;
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

This hook is very simple, but helps us clean up our code a bit. We no longer need to import `WebViewerContext` in all our components.

Let's go back and update our LoadDocument component:

{% tabs %}
{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
// src/components/LoadDocument.js

import useInstance from 'src/hooks/useInstance'
import { useEffect, useRef } from 'react';

export default function LoadDocument() {

   const instance = useInstance();

   const load = () => {
      instance.UI.loadDocument('http://yourwebsite.com/file.pdf')
   }

   return (
     <button onClick={load}>Load document</button>
   )
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

As you can see, leveraging React context to share state across multiple components can really improve your code readability and prevents the need for prop drilling.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/get-started/faq/react-global-instance.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
