MapStore2 icon indicating copy to clipboard operation
MapStore2 copied to clipboard

Update plugins dev documentation

Open allyoucanmap opened this issue 3 years ago • 0 comments

Description

We should update the plugins dev documentation including information of latest improvements:

  • [ ] review code style (eg, use of function instead of classes, import/export instead of require ...)
  • [ ] how to use of createPlugin function
  • [ ] how to create of a plugin
  • [ ] how to create of a map support plugin
  • [ ] how to access context properties available in a plugin (eg, messages, ...)
  • [ ] how to access to items and containers concept and properties
  • [ ] use of react lazy and suspense to optimize the loading of component dependencies
  • [ ] use of new store api

Documentation section involved

  • [x] Developer Guide

Other useful information

Technically with the new store api we could move the reducers/epics registration in a component lifecycle. This could be a good option in case we add heavy dependencies in reducers or epics and in this way we could dynamcally load everything when the plugin component is actually mounted in the UI.

In this example below show a possible implementation where the registration of reducers and plugin is done via an useStoreManager hook. The Example plugin could be moved to another file and loaded with lazy and suspense with this kind of approach. The code below has not being tested yet and it will not work in an extension because StateUtils is only accessible to the main bundle.

import { useEffect } from 'react';
import { normalizeName } from '../utils/PluginsUtils';
import { getStore } from '../utils/StateUtils';

const useStoreManager = (name, {
    reducers,
    epics,
    removeReducers,
    muteEpics
}, dependencies = []) => {
    useEffect(() => {
        const key = normalizeName(name);
        const store = getStore();
        if (reducers) {
            Object.keys(reducers).forEach((reducerKey) => store.storeManager.addReducer(reducerKey, reducers[reducerKey]));
        }
        if (epics) {
            store.storeManager.addEpics(key, epics);
            store.storeManager.unmuteEpics(key);
        }
        return () => {
            if (reducers && removeReducers) {
                Object.keys(reducers).forEach((reducerKey) => store.storeManager.removeReducer(reducerKey));
            }
            if (epics && muteEpics) {
                store.storeManager.muteEpics(key);
            }
        };
    }, dependencies);
};

export default useStoreManager;
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { Observable } from 'rxjs';
import { createPlugin, normalizeName } from '../utils/PluginsUtils';
import useStoreManager from '../hooks/useStoreManager';

const CLICK = 'CLICK:TEST_ACTION';
const click = () => ({ type: CLICK });

const reducers = {
    example: function mapviews(state = {}, action) {
        switch (action.type) {
        case CLICK:
            return { ...state, count: (state.count || 0) + 1 };
        default:
            return state;
        }
    }
};

const epics = {
    exampleStream: (action$) => action$.ofType(CLICK)
        .switchMap((action) => {
            console.log(action);
            return Observable.empty();
        })
};

const PLUGIN_NAME = 'Example';

function Example({ onClick }) {
    useStoreManager({
        name: PLUGIN_NAME,
        reducers,
        epics
    });
    return (
        <button id="example" onClick={onClick} style={{ position: 'absolute', zIndex: 1000 }}>
            TEST
        </button>);
}

const ConnectedExample = connect(() => ({}), { onClick: click })(Example);

export default createPlugin(PLUGIN_NAME, {
    component: ConnectedExample
});

allyoucanmap avatar Sep 02 '22 15:09 allyoucanmap