See the demo: http://michogarcia.org/mapbox-redux
A basic example showing how to use Mapbox with Redux.
$ git clone [email protected]:michogar/mapbox-redux.git
$ cd mapbox-redux
$ npm install
$ npm run start
This sample uses the mapbox-gl-redux library. More docs there.
With the mapbox-gl-redux library we can sync the map's state with the app state and maintain it. To do this, first:
const map = new Mapboxgl.Map({
container: 'map',
style: ''
})
map.addControl(new MapboxGLRedux.ReduxMapControl('map'))
This control gets events from the map and dispatches Redux actions
First, we must create our reducers to create the store
import { MapActionTypes } from '@mapbox/mapbox-gl-redux'
const reducer = (state, action) => {
const map = action.map
switch (action.type) {
case MapActionTypes.zoom:
return Object.assign({}, state, {
zoom: map.getZoom()
})
default:
return state
}
}
export default reducer
Using MapActionTypes
we can identify the actions launched by the map from our reducers
Then, we are able to create the application's store
import { applyMiddleware, createStore } from 'redux'
import * as MapboxGLRedux from '@mapbox/mapbox-gl-redux'
import reducer from './reducer'
const mapMiddleware = MapboxGLRedux.mapMiddleware
const store = createStore(
reducer,
applyMiddleware(mapMiddleware)
)
export default store
With the applyMiddleware
function from Redux we apply our MapboxGLRedux.mapMiddleware
to our store. Now we are able
to launch mapActions
and our map state will be modified with them.
Every action must be linked to the map. The ReduxMapControl
has a MapActionCreators
attribute that returns the whole
actions, but already synced. So, we must instantiate the control with the mapId
before we get the actions through
the MapActionCreators
.
constructor (parent, control, store) {
this.store = store
this.actions = control.MapActionCreators
...
zoomIn () {
this.store.dispatch(this.actions.zoomIn())
}
To connect controls to the map will need to connect the control to the store. As we aren't using React, or something similar, to get the store into the control this will be passed as a parameter of the control's constructor.
class Compass {
constructor (parent, control, store) {
this.store = store
const { bearing } = this.store.getState()
...
According to the Redux pattern, we need a callback to subscribe to the store which will be called by the reducer:
...
this.unsubscriber = store.subscribe(this.onChangeDirection.bind(this))
this.render()
}
onChangeDirection () {
const { bearing } = this.store.getState()
this.bearing = bearing
this.render()
}
In the reducer
we can initialize the map's state
const initialState = {
bearing: 0
}
const reducer = (state = initialState, action) => {
const map = action.map
and to sync the map's states after its loaded we'll use the MapActionCreators.sync()
action:
map.on('load', () => {
const reduxControl = new MapboxGLRedux.ReduxMapControl('map')
map.addControl(reduxControl)
store.dispatch(reduxControl.MapActionCreators.sync())
...
with its correspondent reducer
case MapActionTypes.sync:
return Object.assign({}, state, {
bearing: map.getBearing()
})