2017-09-28 1 views
0

J'ai un composant AdminNav qui a un ensemble d'éléments NavLink afin que je puisse les styler s'ils sont actifs.React Router 4 match propriété

Les sections peuvent également être ouvertes/fermées manuellement pour apparaître moins encombrées.

Ce que je voudrais faire est d'avoir un tas de sections dans le nav, et que la section soit ouverte si elle a un NavLink qui est actif.

AdminNav.js Composant de navigation. Fondamentalement, une liste de 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) 

Donc, si je vais à admin/, la section Cart ouvre comme prévu. Si je vais à admin/view-orders, la section Cart comme prévu. Toutefois, si je vais à admin/view-orders/123 aucun chemin pour le tableau NavLink ne correspond à la section open.

adminRoutes.js Ceci est juste un fichier de routage qui stocke toutes mes routes d'administration. Ce n'est pas entièrement montré ici.

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 La route admin mère. Cela a le AdminNav, et la voie de la volonté de l'une des routes enfant admin comme décrit dans 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 

Y at-il une meilleure façon d'aller à ce sujet? Est-ce que je peux accéder à l'itinéraire complet correspondant de ce composant? Ou est-ce

+0

Je ne suis pas sûr que ce soit juste une faute de frappe sur stackoverflow ou un type dans votre système qui pourrait être la raison pour laquelle les routes ne fonctionnent pas. Vous avez '' '' '' admin/view-order/123''' comme URL et '' '"/admin/view-orders /: id? "' '' Comme route. L'URL est au singulier '' '' order''' et la route est configurée au pluriel - '' 'view-orders''' –

+0

Typo. Mise à jour de la question Pardon! – Gurnzbot

Répondre

0

Je pense que vous devez utiliser le children function prop of routes.

Le composant Route prend une fonction comme un enfant (au lieu de React éléments traditionnellement. Cette fonction est appelée avec un objet comme argument. Ce que nous recherchons pour est la propriété {match}. Si les matches de route alors sa valeur sera l'objet match classique passé par la route, sinon il sera 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> 
    ); 
    } 
} 

dans cet exemple, je rends toujours quelque chose dans le routeur « autre », je viens de tester si la route est correspond et met à jour le message en conséquence. que l'autre route ne change jamais, qu'elle corresponde ou non.