dev-docs/RFCs/v6.0/react-api-rfc.md
Describes a more flexible system for using the multi-view feature with React.
As of v5.x, the DeckGL React component is a thin wrapper of the core Deck class. The user props passed to the React component are passed as-is to the underlying Deck class. With the API changes in v5.3 and v6.0, primarily related to the multi-view feature, the existing system is encountering several problems, as detailed below.
With the new auto-resize and auto-control features in v5.3, the underlying Deck instance is now stateful. To make sure that all children are properly re-rendered, the DeckGL component now calls this.forceUpdate() in multiple event callbacks.
forceUpdate is discouraged by React for the many side effects it may introduceinitialViewState prop to DeckGL instead of viewState. The Deck canvas is updated one tick ahead of the React children.Although props such as width, height, views, viewState, onViewStateChange are marked as optional on the core Deck class, in order to correctly display a base map component as child, some must not be skipped:
<DeckGL
layers={layers}
views={new MapView({id: 'map', controller: MapController})}
{...this.state.viewState}
onViewStateChange={({viewState}) => this.setState({viewState})}
>
<StaticMap
viewId="map"
{...this.state.viewState}
mapStyle={mapStyle}
mapboxApiAccessToken={mapboxApiAccessToken}
/>
</DeckGL>
views and viewId are required for StaticMap to receive dynamic width and height props.onViewStateChange callback is required because DeckGL does not pass viewState to its children.viewId is a non-standard prop and causes warnings when assigned to components such as div.width and height would still be overwritten to the viewport size during render, which may cause render problems.componentWillReceiveProps is now marked unsafe and will be removed in the next major version.
DeckGL accepts render callbacks as children. This is a common React pattern used by libraries such as react-motion and react-virtualized.
viewId to subscribe to changes in the default view.Stateless example:
<DeckGL
layers={layers}
viewState={this.state.viewState}
onViewStateChange={({viewState}) => this.setState({viewState})}
controller={MapController}
>
{({width, height, viewState, viewport}) => <StaticMap
width={width}
height={height}
viewState={this.state.viewState}
mapStyle={mapStyle}
mapboxApiAccessToken={mapboxApiAccessToken}
/>}
</DeckGL>
Statefull example:
<DeckGL
layers={layers}
initialViewState={INITIAL_VIEW_STATE}
onViewStateChange={console.log}
controller={MapController}
>
{({width, height, viewState, viewport}) => <StaticMap
width={width}
height={height}
viewState={viewState}
mapStyle={mapStyle}
mapboxApiAccessToken={mapboxApiAccessToken}
/>}
</DeckGL>
Using react-map-gl components:
<DeckGL
layers={layers}
initialViewState={INITIAL_VIEW_STATE}
controller={MapController}
>
{({width, height, viewState, viewport}) => labels.map(label => (
<Popup
key={label.id}
longitude={label.longitude}
latitude={label.latitude}
viewport={viewport}
>
{label.content}
</Popup>
))}
</DeckGL>
Similar to JSX layers, we can support JSX views. It gives the JSX a cleaner hierarchy in multi-view apps:
<DeckGL
layers={layers}
>
<MapView
initialViewState={INITIAL_MAP_VIEW_STATE}
onViewStateChange={console.log}
controller={MapController}
>
{({width, height, viewState}) => <StaticMap
width={width}
height={height}
viewState={viewState}
mapStyle={mapStyle}
mapboxApiAccessToken={mapboxApiAccessToken}
/>}
</MapView>
<FirstPersonView
initialViewState={INITIAL_FIRST_PERSON_VIEW_STATE}
onViewStateChange={console.log}
controller={FirstPersonController} />
</DeckGL>