react-leaflet's Popup contains a react-route's Link

1.2k views Asked by At

My app uses a react-leaflet for generating a Map with Markers and Popups. And I need to give a link to the other page from Popup by <Link/> component from react-router.

/* app.js */
import React from 'react';
import { render } from 'react-dom';
import { Router, Route, browserHistory } from 'react-router';
import App from './components/App';
import Map from './components/Map';

const Root = () =>
  <Router history={browserHistory}>
    <Route path='/' component={App}>
      <Route path='map' component={Map} />
    </Route>
  <Router>

render(<Root />, document.getElementById('root'));


/* components/Map/index.js */
import React from 'react';
import { Router, Route, browserHistory } from 'react-router';
import App from './components/App';
import Map from './components/Map';

const Map = () =>
  <Map>
    <Marker position={[10, 10]}>
      <Popup>
        <div>
          <Link to="/">Main page</Link>
        </div>
      </Popup>
    </Marker>
  <Map>

export default Map;

But passing through the link I get an error:

<Link>s rendered outside of a router context cannot navigate.

It is because the content of opened Popup is removed from router context and is placed below.

I suppose, that I can to put router.push() into Popup. But maybe is it possible to use a <Link/>?

Thanks!

1

There are 1 answers

0
Alexandr On BEST ANSWER

So, I created ContextProvider component-creator:

import React, { PureComponent, PropTypes } from 'react';

export default function createContextProvider(context) {
  class ContextProvider extends PureComponent {
    static propTypes = {
      children: PropTypes.node,
    };
    static childContextTypes = {};

    getChildContext() {
      return context;
    }

    render() {
      return this.props.children;
    }
  }

  Object.keys(context).forEach((key) => {
    ContextProvider.childContextTypes[key] = PropTypes.any.isRequired;
  });

  return ContextProvider;
}

And used it in the creation of maps marker:

import React, { PureComponent, PropTypes } from 'react';
import { Marker, Popup } from 'react-leaflet';
import createContextProvider from '../ContextProvider';

export default class SomeComponent extends PureComponent {
  static contextTypes = {
    router: PropTypes.object,
    // Place here any other parameters from context
  };

  render() {
    const { position, children, ...props } = this.props;
    const ContextProvider = createContextProvider(this.context);

    return (
      <Marker {...props} position={position}>
        <Popup>
          <ContextProvider>
            <div>
              {children}
            </div>
          </ContextProvider>
        </Popup>
      </Marker>
    );
  }
}