Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(react) React widgets and useWidget hook documentation #9309

Merged
merged 16 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions docs/api-reference/react/deckgl.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,20 @@ const App = (data) => (
);
```

Like any React component, `DeckGL` can accept child components. Child components are often maps (e.g. the `StaticMap` component from react-map-gl), but can be any React components.
Like any React component, `DeckGL` can accept child components. Child components are often maps (e.g. the `Map` component from react-map-gl), but can be any React components, like deck.gl [Widgets](./overview.md#using-react-wrapped-widgets).
chrisgervang marked this conversation as resolved.
Show resolved Hide resolved

```js
import DeckGL from '@deck.gl/react';
import {StaticMap} from 'react-map-gl';
import {Map} from 'react-map-gl/maplibre';
import 'maplibre-gl/dist/maplibre-gl.css';

const App = (data) => (
<DeckGL
initialViewState={{longitude: -122.45, latitude: 37.78, zoom: 12}}
controller={true}
layers={[new ScatterplotLayer({data})]}
>
<StaticMap
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be good to do an audit for this and use maplibre since it doesn't need a token.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea - Add a bullet to our v9.1 tracker task?

mapStyle="mapbox://styles/mapbox/dark-v9"
mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN} />
<Map mapStyle="https://basemaps.cartocdn.com/gl/positron-gl-style/style.json" />
</DeckGL>
);

Expand All @@ -55,7 +54,10 @@ A [Context.Provider](https://reactjs.org/docs/context.html#contextprovider) comp

- `viewport` ([Viewport](../core/viewport.md)) - the current viewport
- `container` (DOMElement) - the DOM element containing the deck canvas
- `eventManager` ([EventManager](https://uber-web.github.io/mjolnir.js/docs/api-reference/event-manager))
- `eventManager` ([EventManager](https://visgl.github.io/mjolnir.js/docs/api-reference/event-manager))
- `onViewStateChange` ([onViewStateChange](../core/deck.md#onviewstatechange)) - the view state change handler
- `deck` ([Deck](../core/deck.md)) - the current deck instance, if present
- `widgets` ([Widget](../core/widget.md)[]) - the current jsx widgets, if any

```jsx
/// Example using react-map-gl v6 controls with deck.gl
Expand All @@ -81,7 +83,7 @@ The following semantics of the standard React `children` property are considered
It is possible to use JSX syntax to create deck.gl layers as React children of the `DeckGL` React components, instead of providing them as ES6 class instances to the `layers` prop.

```jsx
<DeckGL {...viewState}>
<DeckGL initialViewState={...viewState}>
<LineLayer id="line-layer" data={data} />
<DeckGL />
```
Expand Down Expand Up @@ -117,6 +119,17 @@ If a certain view id is used in both JSX views and the `views` prop, the view in
<DeckGL />
```

#### JSX Widgets

It is possible to use JSX syntax to create deck.gl widgets as React children of the `DeckGL` React components, instead of providing them as ES6 class instances to the `widgets` props.

```jsx
<DeckGL initialViewState={...viewState}>
<ZoomWidget id="zoom-widget" placement="top-right" />
<DeckGL />
```

Learn how to use widgets in JSX by reading [Using React-wrapped widgets](./overview.md#using-react-wrapped-widgets).

#### Position Children in Views

Expand Down
56 changes: 56 additions & 0 deletions docs/api-reference/react/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# @deck.gl/react

This module integrates deck.gl with React. First-time deck.gl developers may find it helpful to read [Using deck.gl with React](../../get-started/using-with-react.md) before getting started.

This module contains the following:

### React Components

- [\<DeckGL/>](./deckgl.md)
- Widgets in the [`@deck.gl/widgets`](../widgets/overview.md) module are re-exported as React components in this module.
- e.g. `import { ZoomWidget } from '@deck.gl/react';`

### React Hooks

- [useWidget](./use-widget.md)

## Installation

### Install from NPM

```bash
npm install deck.gl
# or
npm install @deck.gl/core @deck.gl/react
```

```jsx
import DeckGL from '@deck.gl/react';

<DeckGL/>
```

## Using React-wrapped Widgets

Here's a typical example of how to switch from using pure-js widgets in the [`@deck.gl/widgets`](../widgets/overview.md) module to their React-equivalent:

```diff
-import { ZoomWidget } from '@deck.gl/widgets';
+import { ZoomWidget } from '@deck.gl/react';

-<DeckGL widgets={[new ZoomWidget({})]}>
+<DeckGL>
+ <ZoomWidget/>
</DeckGL>
```

React props are passed to the widget:

```diff
-new ZoomWidget({ id: 'zoom', placement: 'top-right' })
+<ZoomWidget id='zoom' placement='top-right'/>
```

### Authoring Custom Widgets with React

Learn how author your own custom widgets in React with the `useWidget` hook by reading the [Custom Widget Developer Guide](../../developer-guide/custom-widgets/).
78 changes: 78 additions & 0 deletions docs/api-reference/react/use-widget.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# useWidget

The `useWidget` hook is used to create React wrappers for normal (non-React) deck.gl widgets, or to create custom widgets with UI rendered by React.

## Usage

```tsx
// React wrapper usage
import DeckGL, {useWidget} from '@deck.gl/react';
import {CompassWidget as UniversalCompassWidget, type CompassWidgetProps} from '@deck.gl/react';

const CompassWidget = (props: CompassWidgetProps) => {
const widget = useWidget(UniversalCompassWidget, props);
return null;
}

<DeckGL>
<CompassWidget/>
</DeckGL>
```

For a custom widget, React can be used to implement the UI itself. A widget class is used to hook into deck.gl apis, and a React [`portal`](https://react.dev/reference/react-dom/createPortal) is utilized to render the widget UI along-side other widgets.

```tsx
import React, {useMemo} from 'react';
import type {Widget} from '@deck.gl/core';
import DeckGL, {useWidget} from '@deck.gl/react';
import {createPortal} from 'react-dom';

class MyWidget implements Widget {
constructor(props) {
this.props = { ...props };
}

onAdd() {
return this.props.element; // HTMLDivElement
}
}

const MyReactWidget = (props) => {
const element = useMemo(() => document.createElement('div'), []);
const widget = useWidget(MyWidget, {...props, element});
return createPortal(
<div>Hello World</div>,
element
);
};

<DeckGL>
<MyReactWidget/>
</DeckGL>
```

See a full example [here](../../developer-guide/custom-widgets/react-widgets.md).

## Signature

```tsx
useWidget<T extends Widget, PropsT extends {}>(
WidgetClass: {new (props: PropsT): T},
props: PropsT
): T
```

The hook creates an [`Widget`](../core/widget.md) instance, adds it to deck.gl, and removes it upon unmount.

Parameters:

- `WidgetClass`: `{new (props: PropsT): T}` - called to create an instance of the control.
- `props`: `PropsT` - props passed into the widget constructor on creation and `widget.setProps` on render.

Returns:

[`Widget`](../core/widget.md) - the widget instance of `WidgetClass`.

## Source

[modules/react/src/utils/use-widget.ts](https://github.com/visgl/deck.gl/blob/master/modules/react/src/utils/use-widget.ts)
7 changes: 5 additions & 2 deletions docs/get-started/using-with-react.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,16 @@ The vis.gl community maintains two React libraries that seamlessly work with dec
- `react-map-gl` - a React wrapper for [Mapbox GL JS](https://docs.mapbox.com/mapbox-gl-js/guides) and [MapLibre GL JS](https://maplibre.org/maplibre-gl-js/docs/). Several integration options are discussed in [using with Mapbox](../developer-guide/base-maps/using-with-mapbox.md).
- `@vis.gl/react-google-maps` - a React wrapper for [Google Maps JavaScript API](https://developers.google.com/maps/documentation/javascript). See [using with Google Maps](../developer-guide/base-maps/using-with-google-maps.md).

## Using JSX Layers and Views
## Using JSX Layers, Views, and Widgets

It is possible to use JSX syntax to create deck.gl layers and views as React children of the `DeckGL` React components, instead of providing them as ES6 class instances to the `layers` prop. There are no performance advantages to this syntax but it can allow for a more consistent, React-like coding style.
It is possible to use JSX syntax to create deck.gl layers, views, and widgets as React children of the `DeckGL` React components, instead of providing them as ES6 class instances to the `layers`, `views`, or `widgets` prop, respectively. There are no performance advantages to this syntax but it can allow for a more consistent, React-like coding style.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is worth mentioning that the basic JSX support is very limited and link to new sections like React Widgets pages.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is done below already with:

For more information on this syntax and its limitations, see DeckGL API.

The relevant section for JSX is under "## Children"


```jsx
import React from 'react';
import DeckGL from '@deck.gl/react';
import {MapViewState} from '@deck.gl/core';
import {LineLayer} from '@deck.gl/layers';
import {ZoomWidget} from '@deck.gl/react';
import {Map} from 'react-map-gl';

const INITIAL_VIEW_STATE: MapViewState = {
Expand All @@ -83,6 +84,8 @@ function App() {
</MapView>

<FirstPersonView width="50%" x="50%" fovy={50} />

<ZoomWidget/>
</DeckGL>
);
}
Expand Down
4 changes: 3 additions & 1 deletion docs/table-of-contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,9 @@
"type": "category",
"label": "@deck.gl/react",
"items": [
"api-reference/react/deckgl"
"api-reference/react/overview",
"api-reference/react/deckgl",
"api-reference/react/use-widget"
]
},
{
Expand Down
Loading