|
| 1 | +# `@perspective-dev/react` |
| 2 | + |
| 3 | +[](https://www.npmjs.com/package/@perspective-dev/react) |
| 4 | + |
| 5 | +React bindings for [Perspective](https://perspective-dev.github.io/), an |
| 6 | +interactive analytics and data visualization component for large, real-time |
| 7 | +and streaming datasets. This package wraps the |
| 8 | +[`<perspective-viewer>`](https://perspective-dev.github.io/viewer/modules/perspective-viewer.html) |
| 9 | +Custom Element in an idiomatic, declarative React component, |
| 10 | +`<PerspectiveViewer>`, which manages the element's imperative |
| 11 | +`load()`/`restore()`/`delete()` lifecycle for you. |
| 12 | + |
| 13 | +## Installation |
| 14 | + |
| 15 | +```bash |
| 16 | +npm install @perspective-dev/react |
| 17 | +``` |
| 18 | + |
| 19 | +`@perspective-dev/client` and `@perspective-dev/viewer` are installed as |
| 20 | +dependencies, but you'll also want at least one plugin package for the |
| 21 | +visualizations themselves: |
| 22 | + |
| 23 | +```bash |
| 24 | +npm install @perspective-dev/viewer-datagrid @perspective-dev/viewer-charts |
| 25 | +``` |
| 26 | + |
| 27 | +## Setup |
| 28 | + |
| 29 | +Perspective's engine and UI are WebAssembly binaries which must be initialized |
| 30 | +once, before the first `<PerspectiveViewer>` renders. Plugins register |
| 31 | +themselves via import side effects. See the |
| 32 | +[User Guide's bundling section](https://perspective-dev.github.io/guide/how_to/javascript/importing.html) |
| 33 | +for bundler configuration details. |
| 34 | + |
| 35 | +```tsx |
| 36 | +import perspective from "@perspective-dev/client"; |
| 37 | +import perspective_viewer from "@perspective-dev/viewer"; |
| 38 | +import "@perspective-dev/viewer-datagrid"; |
| 39 | +import "@perspective-dev/viewer-charts"; |
| 40 | +import "@perspective-dev/viewer/dist/css/themes.css"; |
| 41 | + |
| 42 | +import SERVER_WASM from "@perspective-dev/server/dist/wasm/perspective-server.wasm"; |
| 43 | +import CLIENT_WASM from "@perspective-dev/viewer/dist/wasm/perspective-viewer.wasm"; |
| 44 | + |
| 45 | +await Promise.all([ |
| 46 | + perspective.init_server(fetch(SERVER_WASM)), |
| 47 | + perspective_viewer.init_client(fetch(CLIENT_WASM)), |
| 48 | +]); |
| 49 | +``` |
| 50 | + |
| 51 | +## Usage |
| 52 | + |
| 53 | +Create a `Table` (here in a Web Worker `Client`) and pass it — or a `Promise` |
| 54 | +of it — to `<PerspectiveViewer>`: |
| 55 | + |
| 56 | +```tsx |
| 57 | +import * as React from "react"; |
| 58 | +import { PerspectiveViewer } from "@perspective-dev/react"; |
| 59 | + |
| 60 | +const WORKER = await perspective.worker(); |
| 61 | + |
| 62 | +const TABLE = WORKER.table( |
| 63 | + fetch("superstore.lz4.arrow").then((resp) => resp.arrayBuffer()), |
| 64 | + { name: "superstore" }, |
| 65 | +); |
| 66 | + |
| 67 | +const App: React.FC = () => ( |
| 68 | + <PerspectiveViewer |
| 69 | + client={TABLE} |
| 70 | + config={{ group_by: ["State"], plugin: "Y Bar" }} |
| 71 | + /> |
| 72 | +); |
| 73 | +``` |
| 74 | + |
| 75 | +## Props |
| 76 | + |
| 77 | +| Prop | Type | Description | |
| 78 | +| :--------------- | :------------------------------------------------------------ | :-------------------------------------------------------------- | |
| 79 | +| `client` | `Client \| Table \| Promise<Client> \| Promise<Table>` | Data source. When `undefined`, the viewer `eject()`s. | |
| 80 | +| `config` | `ViewerConfigUpdate \| WorkspaceConfigUpdate` | Declarative viewer state, applied via `restore()`. | |
| 81 | +| `onConfigUpdate` | `(config: ViewerConfigUpdate) => void` | Called when the user reconfigures the viewer through its UI. | |
| 82 | +| `onClick` | `(detail: PerspectiveClickEventDetail) => void` | Called when the user clicks a datapoint. | |
| 83 | +| `onSelect` | `(detail: PerspectiveSelectEventDetail) => void` | Called when the user selects (or deselects) a datapoint or row. | |
| 84 | + |
| 85 | +A subset of standard HTML attributes — `className`, `id`, `style`, `hidden`, |
| 86 | +`slot`, `tabIndex` and `title` — is forwarded to the underlying element. |
| 87 | + |
| 88 | +### `client` |
| 89 | + |
| 90 | +The viewer's data source, forwarded to |
| 91 | +[`viewer.load()`](https://perspective-dev.github.io/viewer/modules/perspective-viewer.html) |
| 92 | +whenever it changes: |
| 93 | + |
| 94 | +- A `Table` (or `Promise<Table>`) displays that table directly. |
| 95 | +- A `Client` (e.g. from `perspective.worker()` or a WebSocket connection to a |
| 96 | + remote server) connects the viewer to every table hosted by that client; |
| 97 | + the table each panel displays is chosen by `config` or interactively by |
| 98 | + the user. |
| 99 | +- `undefined` ejects the viewer, returning it to an unloaded state without |
| 100 | + unmounting it. |
| 101 | + |
| 102 | +The component does not take ownership of the `Table` — delete it yourself |
| 103 | +when it is no longer needed (e.g. `table.delete({ lazy: true })`). |
| 104 | + |
| 105 | +### `config` |
| 106 | + |
| 107 | +Declarative viewer state — group-bys, splits, filters, sorts, expressions, |
| 108 | +plugin and plugin config — applied with `restore()` whenever it (or `client`) |
| 109 | +changes. A config with a `panels` property is treated as a multi-panel |
| 110 | +workspace layout and applied with `restoreWorkspace()` instead. Configs are |
| 111 | +compared structurally, so passing a fresh-but-equal object literal on each |
| 112 | +render does not re-apply. |
| 113 | + |
| 114 | +Combine `config` with `onConfigUpdate` to make the viewer a controlled |
| 115 | +component — store the user's latest configuration in state (or persist it) and |
| 116 | +pass it back down: |
| 117 | + |
| 118 | +```tsx |
| 119 | +const App: React.FC = () => { |
| 120 | + const [config, setConfig] = React.useState<pspViewer.ViewerConfigUpdate>({ |
| 121 | + group_by: ["Category"], |
| 122 | + }); |
| 123 | + |
| 124 | + return ( |
| 125 | + <PerspectiveViewer |
| 126 | + client={TABLE} |
| 127 | + config={config} |
| 128 | + onConfigUpdate={setConfig} |
| 129 | + /> |
| 130 | + ); |
| 131 | +}; |
| 132 | +``` |
| 133 | + |
| 134 | +## Lifecycle |
| 135 | + |
| 136 | +On unmount, the component calls the element's `delete()` method, freeing the |
| 137 | +viewer's WebAssembly resources. Tables and clients are created outside the |
| 138 | +component and are yours to manage; a `Table` passed as `client` survives |
| 139 | +unmount and can be shown again by a later mount. |
| 140 | + |
| 141 | +## See also |
| 142 | + |
| 143 | +- [`react-example`](https://github.com/perspective-dev/perspective/tree/master/examples/react-example) |
| 144 | + — a complete bundler-configured project using this package, including a |
| 145 | + multi-panel workspace config. |
| 146 | +- [Perspective User Guide](https://perspective-dev.github.io/guide/) |
| 147 | +- [`<perspective-viewer>` API documentation](https://perspective-dev.github.io/viewer/modules/perspective-viewer.html) |
| 148 | +- [`@perspective-dev/client` API documentation](https://perspective-dev.github.io/browser/modules/src_ts_perspective.browser.ts.html) |
0 commit comments