react-router v4:判断路由是否已经从组件外部匹配

react-router v4: Determine if route has been matched from outside the component

我有一个组件 总是 需要渲染,但只有在没有匹配的路由时才应该可见 (<Iframe isVisible={ifNoRoutesMatched} />)。

到目前为止,我还没有找到一个很好的方法来检查是否是这种情况。我走下了这条可怕的路线,将变量设置为组件包装器状态,但必须有更好的方法!?这也需要 withRouterPureComponent 否则 catchAllWrapper 会导致无限渲染循环:

class App extends PureComponent {
  state = {
    routeMatched: false,
  }

  catchAllWrapper = () => {
    this.setState({ routeMatched: false });
    return null;
  }

  routeWrapper = (RouteComponent) => {
    const RouteWrapper = (props) => {
      this.setState({ routeMatched: true });
      return <RouteComponent {...props} />;
    };

    return RouteWrapper;
  }

  render() {
    return (
      <div className="App">
        <Navigation />
        <Switch>
          <Route path="/chat" component={this.routeWrapper(Chat)} />
          ...more routes...
          <Route component={this.catchAllWrapper} />
        </Switch>
        <Iframe isVisible={!this.state.routeMatched} />
      </div>
    );
  }
}

export default withRouter(App);

我宁愿手动比较路由字符串数组,也不愿增加这种复杂性!

this.props.match 只有在匹配组件内部匹配的路由信息​​,所以它没什么用。

有更好的方法吗?

用例:它是一个 iframe,在某些路由上加载了遗留应用程序,因此不应在路由之间销毁和重新呈现它

要在没有路由匹配时显示组件,您可以使用以下代码:

               <Switch>                  
                {this.props.notLoggedIn === true
                  ? <Route path='/' component={LandingPage}/>                                          
                  : <Dashboard />                    
                }
                <Route component={PageNotFound}/>
              </Switch>    

在上述情况下,我将登录页面显示为默认路由,如果用户已登录,则会显示仪表板(包含更多路由,例如您的聊天路由)。

如果没有匹配的路由,则显示 PageNotFound 组件。

有关工作示例,请随时查看:https://github.com/osamamaruf/reactnd-project-would-you-rather/blob/master/src/components/App.js
回购 link 是:https://github.com/osamamaruf/reactnd-project-would-you-rather

为什么不为路由器创建一个轻量级虚拟组件以自由挂载和卸载,然后将当前 class 的回调方法绑定到其生命周期事件?

class Dummy extends Component {
  componentDidMount() {
    this.props.didMount();
  }

  componentWillUnmount() {
    this.props.willUnmount();
  }

  render() {
    return null;
  }
}

class App extends Component {
  state = {
    showIframe: false,
  }

  cbDidMount = () => {
    this.setState({ showIframe: true });
  }

  cbWillUnmount = () => {
    this.setState({ showIframe: false });
  }

  render() {
    return (
      <div className="App">
        <Navigation />
        <Switch>
          <Route path="/chat" component={Chat} />
          {/* more routes */}
          <Route render={() => <Dummy didMount={this.cbDidMount} willUnmount={this.cbWillUnmount} />} />
        </Switch>
        <Iframe isVisible={this.state.showIframe} />
      </div>
    );
  }
}

这应该可以为您完成。在组件内部使用 Route that does not have a path property (these always render) and you can check for a null match

这是一个有效的CodeSandBox Example

打开底部的控制台可以看到一直在渲染