How to...

Glue42 Enable Your App

React

Overview

The Glue42 React Hooks package is a library providing custom React hooks for the Glue42 Javascript libraries - @glue42/desktop, if you are working on a Glue42 Enterprise project, or @glue42/web, if you are working on a Glue42 Core project. The examples below use the Glue42 Desktop library. The Glue42 React Hooks library allows you to start using Glue42 features in your React apps idiomatically in the context of the React framework.

Legacy React Wrapper

If you are using the legacy Glue42 React wrapper, @glue42/glux, you can download the documentation for it from here. The documentation on this site is relevant only to the new light-weight Glue42 React wrapper - @glue42/react-hooks.

Prerequisites

The Glue42 React Hooks library comes with the latest version of Glue42 Enterprise, but requires the React and ReactDOM libraries installed. To install the packages, navigate to the root directory of your project and run:

npm install --save @glue42/react-hooks react react-dom

Library Features

The Glue42 React Hooks library offers a way to consume the APIs of the Glue42 Desktop library in your web applications via React Hooks and React Context. The Glue42 React Hooks library provides the following features described below.

Context

The GlueProvider is a React context provider component. It invokes a factory function (with default or user-defined configuration) which initializes the Glue42 Desktop library. The glue object returned from the factory function is set as the context value.

Below is the signature of the GlueProvider component:

GlueProviderProps {
    children: ReactNode;
    glueFactory: (config?: Glue42Web.Config | Glue42.Config) => Promise<Glue42Web.API | Glue42.Glue>;
    fallback?: NonNullable<ReactNode> | null;
    config?: Glue42Web.Config;
};

GlueProvider: FC<GlueProviderProps>;
  • children - React components which may contain Glue42 related logic;

  • glueFactory - Factory function used to initialize the Glue42 Desktop library (the factory function returned by either @glue42/web or @glue42/desktop). Defaults to window.Glue.

  • fallback - Optional. A React component to display while initializing Glue42;

  • config - Optional. A Config object for the Glue() factory function.;

  • GlueContext

GlueContext is the React context which is used by the GlueProvider component. You can consume this context from anywhere inside you app with the default React hook useContext().

GlueContext: Context<Glue42Web.API | Glue42.Glue>;

Hooks

The useGlue() hook is a React hook which will invoke the callback that you pass to it.

Below is the signature of useGlue():

<T = undefined>(
    cb: (glue: Glue42Web.API | Glue42.Glue, ...dependencies: any[]) => void | T | Promise<T>,
    dependencies?: any[]
) => T;
  • cb - Required. A sync/async callback function that will be invoked with the glue object and an array of user-defined dependencies. The callback may or may not include any Glue42-related code;

    • glue - the object returned from the initialization of either the Glue42 Web or Glue42 Desktop libraries;
    • dependencies - additional user-defined arguments for the callback;
  • dependencies - Optional. An array of user-defined variables that will trigger the invocation of the provided callback based on whether the value of any of the specified variables has changed (same functionality as the useEffect() React hook).

  • useGlueInit()

The useGlueInit() hook is a React hook which initializes the provided Glue JS library. It accepts an optional Config object and a Glue42 factory function as arguments.

useGlueInitProps = (
    config: Glue42Web.Config | Glue42.Config,
    glueFactory: GlueProviderProps["glueFactory"]
) => Glue42.Glue;

useGlueInit: useGlueInitProps;
  • config - Optional. A Config object for the Glue() factory function;
  • glueFactory - Optional. Factory function used to initialize the provided Glue JS library. Defaults to window.Glue.

Usage

Below you can see some examples of using the Glue42 React Hooks library.

Initialization

To access the Glue42 Desktop APIs, you need to initialize and (optionally) configure the Glue42 Desktop library. You can do this in two ways - by using the GlueProvider component or the useGlueInit() hook. The difference is that the GlueProvider initializes the Glue42 Desktop library and makes the returned API object (glue) globally available by automatically assigning it as a value to GlueContext, while the useGlueInit() hook initializes the library and returns an API object (glue) which you then have to make available to your other components by passing it as a prop, by creating a context or by attaching it to the global window object.

Add the GlueProvider component by wrapping your other components inside it (preferably the root one). Pass the factory function from @glue42/desktop to the GlueProvider, it will initialize the Glue42 Desktop library and make the Glue42 Desktop APIs available in your application by setting a glue object (returned from the initialization) as the value of GlueContext:

//index.js
import Glue from "@glue42/desktop";
import { GlueProvider } from "@glue42/react-hooks";

ReactDOM.render(
    // Wrap your root component in the `GlueProvider` in order
    // to be able to access the Glue42 Desktop APIs from all child components.
    <GlueProvider fallback={<h2>Loading...</h2>} glueFactory={Glue}>
        <App />
    </GlueProvider>,
    document.getElementById("root")
);

You can also initialize the Glue42 Desktop library with the useGlueInit() hook. Below is an example of conditional rendering of a component based on whether the Glue42 Desktop API is available or not.

import Glue from "@glue42/desktop";
import { useGlueInit } from "@glue42/react-hooks";

const App = () => {
    // Example custom configuration for the Glue42 Web library.
    const config = {
        appManager: true
    }
    const glue = useGlueInit(config, Glue);

    return glue ? <Main glue={glue} /> : <Loader />;
};

export default App;

Remember that when you initialize the Glue42 Desktop library with the useGlueInit() hook, you need to take care of the way you provide the glue object to your nested components. For example, you can use React Context or attach it to the global window variable.

Consuming Glue42 APIs

After the Glue42 Desktop library has been successfully initialized, you can access the Glue42 Desktop APIs with the built-in React hook useContext() passing GlueContext as its argument, or with the useGlue() hook.

Note that this library is just a thin wrapper designed to work with both @glue42/web and @glue42/desktop. For that reason, if you are using React with TypeScript you should type cast the initialized glue object to the appropriate type, because the default type is Glue42Web.API | Glue42.Glue.

Below is an example of accessing the glue object with GlueContext and using the Shared Contexts API to get the context of the current window:

import { useContext, useState, useEffect } from "react";
import { GlueContext } from "@glue42/react-hooks";

const App = () => {
    const [context, setContext] = useState({});
    // Access the Glue42 Desktop APIs by using the `glue` object 
    // assigned as a value to `GlueContext` by the `GlueProvider` component.
    const glue = useContext(GlueContext);

    useEffect(() => {
        setContext(glue.windows.my().context);
    }, []);

    return (
        <div>
            <h2>My Window Context</h2>
            <pre>{JSON.stringify(context, null, 4)}</pre>
        </div>
    );
};

export default App;

Below is an example of accessing the glue object with the useGlue() hook and using the Window Management API to open an app in a new window on button click:

import { useGlue } from "@glue42/react-hooks";

const App = () => {
    const openWindow = useGlue(glue => (name, url) => {
        glue.windows.open(name, url);
    });

    return (
        <table>
            <tr>
                <td>Client List</td>
                <td>
                    <button
                        onClick={() => {
                            openWindow("ClientList", "http://localhost:8080/client-list");
                        }}
                    >
                        Start
                    </button>
                </td>
            </tr>
        </table>
    );
};

export default App;

This is an example of using the Interop API to get the window title through an already registered Interop method:

import { useGlue } from "@glue42/react-hooks";
import { useState } from "react";

const App = () => {
    const [title, setTitle] = useState("");
    const getTitle = useGlue(glue => methodName => {
        glue.interop.invoke(methodName).then(r => setTitle(r.returned._result));
    });
    return (
        <>
            <h2>{title}</h2>
            <button
                onClick={() => {
                    getTitle("T42.Demo.GetTitle");
                }}
            >
                Get Title
            </button>
        </>
    );
};

export default App;

Testing

You can use your own factory function for initializing the Glue42 Desktop library. This is useful in Jest/Enzyme tests when you want to mock the Glue42 library:

//index.js
import { mount } from "enzyme";
import { GlueProvider } from "glue42/react-hooks";

// Define a factory function which will mock the Glue42 Web library.
const glueFactory = () => {
    const glueObject = {
        interop: { invoke: jest.fn(), register: jest.fn() },
        contexts: { subscribe: jest.fn(), update: jest.fn() },
        windows: { open: jest.fn(), my: jest.fn() }
    };

    return Promise.resolve(glueObject);
};

describe("Mock Glue42", () => {
    it("Should mock the Glue42 library.", () => {
        const wrapper = mount(
        // Pass your factory function to the `GlueProvider` component.
        <GlueProvider glueFactory={glueFactory}>
            <App />
        </GlueProvider>
        );
        // Your logic here.
    });
});

For additional information on testing React hooks, see the @testing-library/react-hooks.

Glue42 JavaScript Concepts

Once the Glue42 React library has been initialized, your application has access to all Glue42 functionalities. For more detailed information on the different Glue42 concepts and APIs, see:

Reference

Reference