React Router Link在LeafletJS中无法工作

6

版本:

  • react-router-dom 4.1.1
  • react-router-redux 5.0.0-alpha.4
  • react-leaflet 1.1.3
  • leaflet 1.0.3

复现步骤

我创建了一个leaflet地图,在其中添加了一些标记。这些标记有弹出窗口。 在每个弹出窗口中,我想要有一个<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')
)

期望行为

当弹出窗口打开时,我可以看到我的链接并点击它。

实际行为

Actual behaviour无法看到链接。它没有生成。

额外细节

在我的<MapMode>中,我使用来自leaflet的<Map>。 如果我在<Map>标签上面设置一个<Link>,它就能正常工作。 但是,一旦我想在<Map>内部放置链接,它就会出现问题。 这是我的页面的React结构,<Popup>标记只包含null,因为Javascript出现了故障: React structure

这是一个相当复杂的问题,所以请随时向我提问。 谢谢。


传递给ConnectedRouter的“history”是否有值?看起来它是未定义的。 - Panther
@Panther,如果您查看React结构,它确实具有价值。而且,如果我在<Map>上面设置一个链接,它可以正常工作。 React-router的贡献者建议这可能与LeafletJS创建门户有关?https://github.com/ReactTraining/react-router/issues/4979#event-1045005333 不过,我不知道如何避免这种情况 :( - Vincent Audebert
3个回答

11

我尝试了Tharaka建议的解决方案,但对我无效。看起来react-leaflet的弹出窗口正在使用自己的上下文,因此阻止了从更高级别传递的上下文。但是,受这个解决方案的启发,我想出了另一个解决方案,非常简单且基于组合原则。

我创建了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,
}

1
我无法让选定的答案起作用,但这个方法对我有效。谢谢! - Jason Thuli
在给予Tharaka应有的赞誉的前提下,我认为这个改进且更简单的解决方案在大多数情况下更好。 - Maltronic

4

我对这个答案并不完全确定,但无论如何,我会尝试回答,因为我认为至少可以为将来尝试解决这个问题的任何人提供一些帮助。

我从react-leaflet GitHub存储库中的此问题中得到了第一个提示。根据那个问题和你的错误,似乎问题是Popup无法从上下文中访问router,因为context没有通过它们渲染Popup时传递给它。因此,如果我们能够显式地将上下文传递给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;
}

假设您正在组件MapMaker中使用弹出窗口,则可以使用高阶组件将上下文router注入到弹出窗口中,如下所示。

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
    );
  }

}

太好了!我刚刚创建了一个 LinkWithContext 而不是 PopupWithContext,它对我起作用了!非常感谢 :) - Vincent Audebert

-1
我的解决方案(这是一个变通方法,但效果很好,我没有看到任何缺点):
我通过在React Router v3中使用Redux来解决问题。
<a onClick={() => goTo(params)} />

goTo 在以下位置被定义:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接