React Router Link не работает с LeafletJS

Версии:

  • Реагировать-маршрутизатор-дом 4.1.1
  • реакция-маршрутизатор-редукс 5.0.0-альфа.4
  • реактивная листовка 1.1.3
  • листовка 1.0.3

Действия по воспроизведению

Я создаю карту листовок. В котором я добавляю несколько маркеров. Эти маркеры имеют всплывающие окна. В каждом из этих всплывающих окон я хочу иметь <Link>

Также, если это поможет, это моя конфигурация маршрутизации:

ReactDOM.render(
  <Provider store={store}>
    <div>
      <AppContainer />
      <ConnectedRouter history={history}>
        <div>
          <MenuContainer />
          <Switch>
            <Route path='/:area/:sport/list' component={ListContainer} />
            <Route path='/:area/:sport/map' component={MapContainer} />
            <Route path='/:area/:sport/rasp' component={RaspContainer} />
            <Route path='/:shortcode/details' component={StationDetailsContainer} />
            <Redirect exact from='/' to='/wellington/paragliding/list' />
            <Route component={NoMatch} />
          </Switch>
        </div>
      </ConnectedRouter>
    </div>
  </Provider>,
  document.getElementById('root')
)

Ожидаемое поведение

Я вижу свою ссылку и нажимаю на нее, когда открывается всплывающее окно.

Фактическое поведение

Фактическое поведение Невозможно увидеть ссылку. Он не генерируется.

Дополнительные детали

Внутри моего <MapMode> я использую <Map> из листовки. Если я установлю <Link> чуть выше тега <Map>, это сработает. Как только я хочу иметь ссылку внутри своего <Map>, она как-то ломается. Это структура React моей страницы, тег <Popup> содержит только null, так как Javascript ломается: Структура реакции

Это довольно сложная проблема, так что не стесняйтесь задавать мне вопросы. Спасибо.


person Vincent Audebert    schedule 18.04.2017    source источник
comment
Имеет ли значение history, передаваемое в ConnectedRouter? Похоже, он не определен.   -  person Panther    schedule 18.04.2017
comment
@Panther нет, это имеет значение, если вы посмотрите на структуру React. Также, если я устанавливаю ссылку чуть выше ‹Карты›, она работает нормально. Участник React-router предполагает, что он может быть связан с созданием портала LeafletJS? github.com/ReactTraining/react-router/issues/ Хотя не знаю, как этого избежать :(   -  person Vincent Audebert    schedule 18.04.2017


Ответы (3)


Я не уверен на 100% в этом ответе. Но в любом случае я попытаюсь, потому что я думаю, что, по крайней мере, это может пролить свет на любого, кто попытается решить эту проблему в будущем.

Я получил первую подсказку от этой проблемы в react-leaflet репозитории GitHub. В соответствии с этим и вашей ошибкой кажется, что проблема в том, что всплывающее окно не может получить доступ к router из context, потому что context не передается во всплывающее окно так, как они его отображают. Таким образом, мы сможем решить проблему, если сможем явно передать контекст в Popup.

Затем я нашел способ явно передать контекст в компонент в этот ответ StackOverflow. При этом я думаю, что вы должны иметь возможность использовать HoC (компонент более высокого порядка) следующим образом, чтобы решить вашу проблему.

Это HoC, который внедряет контекст в компонент:

function withContext(WrappedComponent, context){

  class ContextProvider extends React.Component {
    getChildContext() {
      return context;
    }

    render() {
      return <WrappedComponent {...this.props} />
    }
  }

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

  return ContextProvider;
}

Допустим, вы используете Popup внутри компонента MapMaker. Затем вы можете внедрить контекст с router в Popup, используя HoC следующим образом.

class MapMaker extends React.Component {

  //......

  // This make sure you have router in you this.context
  // Also you can add any other context that you need to pass into Popup
  static contextTypes = {
    router: React.PropTypes.object.isRequired
  }

  render(){

    const PopupWithContext = withContext(Popup, this.context);

    return (
      //..... your JSX before Popup
      <PopupWithContext/> // with your props
      //..... your JSX after Popup
    );
  }

}
person Tharaka Wijebandara    schedule 24.04.2017
comment
Идеальный! Я только что создал LinkWithContext вместо PopupWithContext, и у меня это сработало! Большое спасибо :) - person Vincent Audebert; 27.04.2017

Я попробовал решение, предложенное Таракой, но оно мне не помогло. Похоже, всплывающее окно реагирующей листовки использует свой собственный контекст, тем самым блокируя контекст, который передается с более высоких уровней. Однако, вдохновленный этим решением, я придумал другое, очень простое и основанное на принципе композиции.

Я создал компонент RouterForwarder

import React, { Component } from 'react'
import PropTypes from 'prop-types'

class RouterForwarder extends Component {
  getChildContext() {
    return this.props.context
  }

  render() {
    return <span>{this.props.children}</span>
  }
}

RouterForwarder.childContextTypes = {
  router: PropTypes.object.isRequired,
}

RouterForwarder.propTypes = {
  context: PropTypes.object.isRequired,
}

export default RouterForwarder

а затем использовал его в моем компоненте (тот, который отображает карту, маркер, всплывающее окно и ссылку) следующим образом:

import RouterForwarder from './RouterForwarder'

class MyComponent extends Component {

  render() {
    return (
    ...
      <Popup>
        <RouterForwarder context={this.context}>
          <Link to={'my destination'}>Go to My Destination</Link>
        </RouterForwarder>
      </Popup>
    ...)
  }
}

MyComponent.contextTypes = {
  router: PropTypes.object,
}
person moniikag    schedule 17.07.2017
comment
Я не мог заставить выбранный ответ работать, но это сработало для меня. Спасибо! - person Jason Thuli; 15.02.2018
comment
С должным уважением к Тараке, я думаю, что это улучшенное и более простое решение лучше в большинстве случаев. - person Maltronic; 23.06.2018

Мое решение (это обходной путь, но он отлично работает, и я не вижу недостатков):

Я решил использовать (в реагирующем маршрутизаторе v3 с redux)

<a onClick={() => goTo(params)} />

тогда как goTo определено в

const mapDispatchToProps = (dispatch) => bindActionCreators({
  goTo(id) {
    return push(`/<url>/${id}`); // push from 'react-router-redux'
  },
}, dispatch);
person dragonmnl    schedule 30.06.2017