React Router Link 不适用于 LeafletJS

版本:

  • react-router-dom 4.1.1
  • react-router-redux 5.0.0-alpha.4
  • 反应传单 1.1.3
  • 传单 1.0.3

重现步骤

我创建了一张传单地图.我在其中添加了一些标记.这些标记有弹出窗口.在每个弹出窗口中,我都希望有一个 <Link>

如果有帮助,这是我的路由配置:

ReactDOM.render(<提供者商店={商店}>

<应用容器/><ConnectedRouter 历史={历史}>

<菜单容器/><开关><Route path='/:area/:sport/list' 组件={ListContainer}/><路线路径='/:area/:sport/map' 组件={MapContainer}/><Route path='/:area/:sport/rasp' 组件={RaspContainer}/><Route path='/:shortcode/details' 组件={StationDetailsContainer}/><从='/' 重定向到='/wellington/paragliding/list'/><路由组件={NoMatch}/></开关></div></连接路由器></div></提供者>,document.getElementById('root'))

预期行为

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

实际行为

无法看到链接.它没有生成.

额外细节

在我的 <MapMode> 中,我使用传单中的 <Map>.如果我在 <Map> 标签上方设置一个 <Link> ,它就可以工作.只要我想在我的 <Map> 中有一个链接,它就会以某种方式中断.这是我页面的 React 结构,<Popup> 标签只包含 null,因为 Javascript 正在破坏:

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

解决方案

我不能 100% 确定这个答案.但无论如何我都会尝试,因为我认为至少它可能会为将来尝试解决此问题的任何人提供一些启示.

我从 react 中的 this issue 得到了第一个提示-leaflet GitHub 存储库.根据那个和你的错误,问题似乎是 Popup 无法从 context 访问 router 因为 context 没有传入以他们呈现的方式弹出窗口.因此,如果我们可以将上下文显式传递给 Popup,我们应该能够解决问题.

然后我找到了一种将上下文显式传递到组件中的方法 this StackOverflow 答案.有了这个,我认为你应该能够使用如下的 HoC(高阶组件)来解决你的问题.

这是向组件注入上下文的 HoC:

function withContext(WrappedComponent, context){类 ContextProvider 扩展 React.Component {getChildContext() {返回上下文;}使成为() {返回 <WrappedComponent {...this.props}/>}}ContextProvider.childContextTypes = {};Object.keys(context).forEach(key => {ContextProvider.childContextTypes[key] = React.PropTypes.any.isRequired;});返回上下文提供者;}

假设您在一个名为 MapMaker 的组件中使用 Popup.然后你可以像这样使用 HoC 将带有 router 的上下文注入到 Popup 中.

类 MapMaker 扩展 React.Component {//......//这确保你有路由器 this.context//您还可以添加需要传递到 Popup 的任何其他上下文静态上下文类型 = {路由器:React.PropTypes.object.isRequired}使成为(){const PopupWithContext = withContext(Popup, this.context);返回 (//..... 你的 JSX 在 Popup 之前<PopupWithContext/>//用你的道具//.....弹出后你的JSX);}}

Versions:

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

Steps to reproduce

I create a leaflet map. In which I add some markers. These markers have popups. In each of these popup I want to have a <Link>

Also if it helps this is my Routing config:

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')
)

Expected Behavior

I can see my link and click on it when popup opens.

Actual Behavior

Impossible to see the link. It's not generated.

Extra details

Inside my <MapMode> I use <Map> from leaflet. If I set a <Link> just above the <Map> tag it works. As soon as I want to have a link inside my <Map>, somehow it breaks. This is the React structure of my page, <Popup> tag just contains null as Javascript is breaking:

It's quite a complex problem so feel free to ask me questions. Thanks.

解决方案

I'm not 100% sure about this answer. But anyway I'm going to try because I think at least it might shed some light to anyone who will try to solve this problem in future.

I got the first hint from this issue in react-leaflet GitHub repo. According to that and your error, it seems the problem is Popup can't access the router from the context because context isn't passed into the Popup with the way they render it. So we should be able to fix the problem if we can explicitly pass the context to Popup.

Then I found a way to explicitly pass the context into a component in this StackOverflow answer. With that, I think you should be able to use a HoC(Higher order Component) as follows to solve your problem.

This is the HoC that inject context to a component:

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

Let's say you are using Popup inside a component called MapMaker. Then you can inject the context with router into Popup using the HoC like this.

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

}

相关文章