React Router 4匹配属性

时间:2017-09-28 14:46:55

标签: javascript reactjs react-router react-router-v4

我有一个AdminNav组件,其中包含一组NavLink元素,因此如果它们处于活动状态,我可以设置它们的样式。

这些部分也可以手动打开/关闭,看起来不那么混乱。

我想要做的是在导航中有一堆部分,如果它有一个活跃的NavLink,则打开该部分。

AdminNav.js 导航组件。基本上是NavLink s。

的列表
import React, { Component } from 'react'
import { NavLink, withRouter } from 'react-router-dom'
import _find from 'lodash/find'

import '../../css/sub-nav.css'

class AdminNav extends Component {

    constructor(props){
        super(props)

        // Shows 'admin/' at all times
        console.log(props.match)

        this.state = {
            sectionRoutes: [
                {
                    title: 'Cart',
                    routes: [
                        {
                            title: 'Dashboard',
                            path: '/admin',
                            exact: true
                        },
                        {
                            title: 'View Orders',
                            path: '/admin/view-orders',
                            exact: false
                        },
                        {
                            title: 'Cart Settings',
                            path: '/admin/settings',
                            exact: true
                        },
                        {
                            title: 'Merchant Settings',
                            path: '/admin/merchant',
                            exact: true
                        }
                    ]
                },
                {
                    title: 'Products',
                    routes: [
                        {
                            title: 'Add Product',
                            path: '/admin/product-add',
                            exact: true
                        },
                        {
                            title: 'Edit Product',
                            path: '/admin/product-edit',
                            exact: true
                        },
                        {
                            title: 'Add Category',
                            path: '/admin/category-add',
                            exact: true
                        },
                        {
                            title: 'Edit Category',
                            path: '/admin/category-edit',
                            exact: true
                        },
                        {
                            title: 'Set Category Order',
                            path: '/admin/category-order',
                            exact: true
                        }
                    ]
                },
                {
                    title: 'User',
                    routes: [
                        {
                            title: 'Logout',
                            path: '/admin/logout',
                            exact: true
                        }
                    ]
                }
            ],
            openSections: []
        }
    }

    handleSectionClick = (sectionTitle) => {
        let titleIndex = this.state.openSections.indexOf(sectionTitle)

        if(titleIndex > -1){
            this.setState({ openSections: this.state.openSections.filter((title, i) => i !== titleIndex)})
        }else{
            this.setState({ openSections: [ ...this.state.openSections, sectionTitle ] })
        }
    }

    isSectionOpen(section){

        const currentPath = this.props.location.pathname

        // Section is open if routh path matches the current path OR section has been manually opened
        // THIS DOES NOT WORK IF section is a route that has optional params (Ex. `admin/view-orders/:id?`)
        const result =  _find(section.routes, route => currentPath === route.path) ||
                        _find(this.state.openSections, title => title === section.title)

        return result
    }

    render() {
        return (
            <div className="sub_nav">
                <div className="title">Admin Menu</div>

                {this.state.sectionRoutes.map(section =>
                    <div key={section.title} className="nav_section">
                        <div className={'section_title' + (this.isSectionOpen(section) ? ' open' : '')} onClick={(e) => this.handleSectionClick(section.title)}>{section.title}</div>
                        <div>
                            {section.routes.map(route =>
                                <NavLink key={route.title} activeClassName="active" to={route.path} exact={!!route.exact}>{route.title}</NavLink>
                            )}
                        </div>
                    </div>
                )}
            </div>
        )
    }
}

export default withRouter(AdminNav)

因此,如果我转到admin/Cart部分会按预期打开。 如果我按预期转到admin/view-orders Cart部分。 但是,如果我转到admin/view-orders/123没有NavLink数组匹配的路径,那么该部分就不会添加open类。

adminRoutes.js 这只是一个存储我所有管理路由的路由文件。这里没有完全显示出来。

import React from 'react'

import AdminDashboard from './AdminDashboard'
import AdminLogout from './AdminLogout'
import AdminOrders from './AdminOrders'

export default [
    {
        path: "/admin",
        exact: true,
        render: (props) => (<AdminDashboard {...props} />)
    },
    {
        path: "/admin/logout",
        component: AdminLogout
    },
    {
        path: "/admin/view-orders/:id?",
        component: AdminOrders
    },
    {
        component: () => <h1 className="no-margin">Page not found</h1>
    }
]

Admin.js 父管理员路由。它具有AdminNav,并将路由到任何管理子路由,如adminRoutes.js

中所述
import React, { Component } from 'react'
import { Switch, Route } from 'react-router-dom'
import AdminNav from './AdminNav'

import routes from './adminRoutes'

class Admin extends Component {
    render() {
        return (
            <div className="full_body_container">
                <div className="sub_nav_wrapper">
                    <div className="hbs-container-admin-nav">
                        <AdminNav />
                    </div>
                </div>
                <div className="content_wrapper">
                    {
                        <Switch>
                            {routes.map((route, i) => <Route key={i} {...route} />)}
                        </Switch>
                    }
                </div>
            </div>
        )
    }
}

export default Admin

还有更好的方法吗?我能从这个组件访问实际完全匹配的路由吗?或者是这个

1 个答案:

答案 0 :(得分:0)

我认为你需要使用children function prop of routes

Route组件将一个函数作为子函数(而不是React) 元素traditionnaly。 以对象作为参数调用此函数。我们在寻找什么 for是{match}属性。如果路线匹配则其值将是 路由传递的经典match对象,否则为null

class App extends Component {
  render() {
      return (
          <Router>
              <div className="App">
                  <header className="App-header">
                      <img src={logo} className="App-logo" alt="logo" />
                      <h1 className="App-title">Welcome to React</h1>
                      <Link to="/other">other route</Link>
                  </header>
                  <Route path="/" exact>
                      {({ match }) => {

                          return <Message />

                      }}
                  </Route>
                  <Route path="/other">
                      {({ match, ...props }) => {

                          console.log(match, props);
                          return <Message text={match ? "this matches" : "does not match"} />

                      }}
                  </Route>

              </div>
          </Router>
      );
  }
}

在这个例子中,我总是在&#39;其他&#39;中呈现一些东西。路由器,我只是测试路由是否匹配并相应地更新消息。您会看到其他路线从未改变是否匹配。