【问题标题】:subpage doesn't match react-router 4子页面与 react-router 4 不匹配
【发布时间】:2018-03-14 20:59:26
【问题描述】:

我的路由器设置是这样的

<Switch>
  <PrivatePage key={index} {...opts} component={(props) => 
     <Section {...props} pages={childRoutes} />
  } />
  <PrivatePage path='/accounts/:id' exact={true}  render={({ match }) => (
    <Redirect to={/accounts/${match.params.id}/profile} />
  )} />
  ...
  <Route component={NotFound} />
</Switch>

然后&lt;Section /&gt;

<SubNavMenu />
<Route path=/accounts/:id/profile componet={ProfilePage} />
<Route path=/accounts/:id/dashboard componet={DashboardPage} />

然后&lt;PrivatePage /&gt; 呈现类似,而&lt;Page /&gt; 只是呈现&lt;Navigation /&gt; {this.props.children}

const PrivatePage = ({ component: Component, ...rest }) => {
  let result = props => (
    <Redirect
      to={{
        pathname: '/redirect',
        state: { from: props.location },
      }}
    />
  )

  if (User.methods.isAuthed()) {
    result = props => (
      <Page>
        <Component {...props} />
      </Page>
    )
  } else if (rest.path === '/') {
    result = props => (
      <Redirect
        to={{
          pathname: '/login',
        }}
      />
    )
  }

  return <Route {...rest} render={props => result(props)} />
}

export default PrivatePage

单击将我带到accounts/:id 的链接正确地将我重定向到个人资料页面,但是当我尝试从 SubNavMenu 转到仪表板页面时,我得到了我的 NotFound 页面并安慰 this.props.match {path: "/", url: "/", params: {…}, isExact: false} 但是我的路径是/accounts/7kB7fRdsu39Be44ou/dashboard

感谢您的帮助


根据请求,部分的完整代码

pages = [
{
  authed: true,
  icon: 'cog',
  component: (<div/>),
  name: 'AccountDetailSection',
  path: `/accounts/:id/profile`, 
},
{
  authed: true,
  component: AccountProfilePage,
  exact: true, 
  getLink: id => `/accounts/${id}/profile`, 
  icon: 'cog',
  label: 'Account',
  name: 'AccountDetailProfile',
  parent: 'AccountDetailSection',
  path: `/accounts/:id/profile`, 
},
{
  authed: true,
  component: AccountDashboardsPage,
  exact: true, 
  getLink: id => `/accounts/${id}/dashboard`, 
  icon: 'cog',
  label: 'Dashboard', 
  name: 'AccountDetailDashboards',
  parent: 'AccountDetailSection',
  path: `/accounts/:id/dashboard`, 
},
]


class PrivateSection extends React.Component<IProps, IState> {
  classes = { // static values
    button:  'App-navigation--listItemButton',
    container: 'App-navigation',
    header: 'App-navigation--header',
    headerLogo: 'App-navigation--headerLogo',
    listContainer: 'App-navigation--list',
    listItem: 'App-navigation--listItem',
    listItemActive: 'App-subnavigation--listItem--active',
    listItemHover: 'App-navigation--listItem--hover',
    positionBottom: 'App-navigation--bottom',
    positionTop: 'App-navigation--top',
  }
  sharedProps = { // static values
    activeClass: this.classes.listItemActive,
    buttonClass:  this.classes.button,
    buttonContainer: this.classes.listItem,
    hoverClass: this.classes.listItemHover,
    menuContainer: this.classes.listContainer,
    onHover: this.handleMouseIn.bind(this),
  }

  constructor(props: IProps) {
    super(props) 

    this.state = {
      hovering: '',
    }
  }

  handleMouseIn(name: string) {
    this.setState({hovering: name})
  }
  handleMouseOut() {
    this.setState({hovering: ''})
  }

  renderSubNav() {
    const navOpts = {
      hovering: this.state && this.state.hovering || '',      
      onHover: this.handleMouseIn.bind(this),
    }

    const navItems: any = this.props.pages.map(p => { // tslint:disable-line no-any
      const o = {...p}

      if (typeof(o.getLink) === 'function') {
        const {id} = this.props.match && this.props.match.params || {id: ''}

        o.link = o.getLink(id)
        o.getLink = undefined
      }

      o.authed = undefined
      o.exact = undefined
      o.component = undefined

      return {...navOpts, ...o}
    })

    const submenuClasses = {
      active: this.sharedProps.activeClass,
      button:  this.sharedProps.buttonClass,
      buttonContainer: this.sharedProps.buttonContainer,
      hover: this.sharedProps.hoverClass,
      menuContainer: this.sharedProps.menuContainer,
    }

    return (
      <div
        className='profile_subnav'
        style={{height: '100%'}}
        onMouseLeave={() => this.handleMouseOut()}
      >
        <Menu
          items={navItems}
          classes={submenuClasses}
        />
      </div>
    )
  }
  renderContent() {
    return (
      <div className='profile_content'>
        {this.props.pages.map((opts, index) => {
          const o: any = {...opts} // tslint:disable-line no-any
          if (typeof(o.getLink) === 'function') {
            const {id} = this.props.match && this.props.match.params || {id: ''}

            o.link = o.getLink(id)
            o.getLink = undefined
          }

          return (
            <PrivateRoute key={index} {...o}/>
          )
        })}
      </div>
    )
  }
  render() {
    return (
      <div
        className='page--content_container'
      >
        {this.renderSubNav()}
        {this.renderContent()}
      </div>
    )
  }
}

export default PrivateSection

&lt;Button /&gt;的渲染方法(被&lt;Menu /&gt;包裹

 render() {
    const {
      activeClass,
      containerClass,
      exactLink,
      hoverClass,
      icon,
      label,
      link,
      onClick,
      handleActive,
    } = this.props

    let message = (
      <div className='Button--message'>
        <div className='Button--messageText'>{label}</div>
      </div>
    )   
    if (icon) {
      message = (
        <div className='Button--message'>
          <div className='Button--messageIcon'><Icon name={icon} / ></div>
          <div className='Button--messageText'>{label}</div>
        </div>
      )    
    }

    const buttonContainerClass = this.isHovering() ? `${containerClass} ${hoverClass}` : containerClass

    const ButtonContainer = props => (
      <button
        {...props}
        className={this.props.buttonClass || ''}
        onMouseEnter={() => this.handleMouseIn()}
        onMouseLeave={() => this.handleMouseOut()}
      >
        {message}
      </button> 
    )

    let Result
    if (typeof(link) === 'string') {
      if (typeof(activeClass) === 'string' && activeClass.length > 0) {
        const opts = {
          activeClassName: activeClass || '',
          className: buttonContainerClass || '',
          exact: exactLink || false,
          isActive: handleActive || undefined,
          strict: true,
          to: link,
        }

        Result = (
          <NavLink {...opts} >
            <ButtonContainer />
          </NavLink>
        )
      } else {
        Result = (
          <Link to={link} className={buttonContainerClass}>
            <ButtonContainer />
          </Link>
        )
      }

    } else if (typeof(onClick) === 'function') {
      Result = (
        <div className={buttonContainerClass}>
          <ButtonContainer onClick={() => onClick()} />
        </div>
      )

    } else {
      console.warn('Button must have an action props> ', {props: this.props})
    }

    return Result
  }

【问题讨论】:

  • 你打算如何进入仪表板?通过Link ?你能展示那件作品吗?
  • 更新了@Panther,我正在使用
  • 您的某些代码中有一些错误,例如您的路线中的道具有一个拼写错误的组件道具,并且您的路线需要在其周围加上引号。 @Falieson
  • @Win 如果我拼错了一些东西,我确信打字稿会抓住它。也许我在这篇文章中拼错了,你能帮我找到你引用的内容吗?

标签: javascript node.js reactjs react-router react-router-dom


【解决方案1】:

我遇到了类似的问题,即 Switch 没有找到用其他组件包装的路由。查看源代码,看起来Switch 确实在子项中递归查找Routes,因此它们不能嵌套。

在这种情况下,要使用Switch,您需要重构以使Route 成为每个路由的顶级组件。或者重构不使用Switch - 基本上使所有路由exact 匹配。

切换来源:https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Switch.js 它使用React.Children.forEach 来查找路径,该路径仅迭代立即子级,而不是嵌套子级。

【讨论】:

  • 我怀疑这可能是问题所在,谢谢 - 我会尝试确认;然后接受等。
  • 再次感谢。我发现路由的容器是exact={false}(notfound页面除外),然后其他一切都需要exact={true}并且开关工作..我认为?
猜你喜欢
  • 2021-10-28
  • 2020-01-11
  • 2022-07-10
  • 2017-09-03
  • 2016-09-02
  • 2017-09-11
  • 2021-03-15
  • 2020-09-04
相关资源
最近更新 更多