2017-08-03 1 views
2

Ich baue eine App mit React, React-Router (v5) und Redux und frage mich, wie auf die Parameter der aktuellen URL in einer übergeordneten Route zugegriffen werden kann.So erhalten Sie Params in der übergeordneten Routenkomponente

Das ist mein Eintrag ist, die router.js:

<Wrapper> 
    <Route exact path="/login" render={(props) => (
    <LoginPage {...props} entryPath={this.entryPath} /> 
)} /> 

    <Route exact path="/" component={UserIsAuthenticated(HomePage)} /> 
    <Route exact path="/about" component={UserIsAuthenticated(AboutPage)} /> 
    <Route path="/projects" component={UserIsAuthenticated(ProjectsPage)} /> 
</Wrapper> 

Und das ist meine ProjectsPage Komponente:

class ProjectsPage extends PureComponent { 
    componentDidMount() { 
    this.props.fetchProjectsRequest() 
    } 

    render() { 
    console.log(this.props.active) 

    if (this.props.loading) { 
     return <Loading /> 
    } else { 
     return (
     <Wrapper> 
      <Sidebar> 
      <ProjectList projects={this.props.projects} /> 
      </Sidebar> 
      <Content> 
      <Route exact path="/projects" component={ProjectsDashboard} /> 

      <Switch> 
       <Route exact path="/projects/new" component={ProjectNew} /> 
       <Route exact path="/projects/:id/edit" component={ProjectEdit} /> 
       <Route exact path="/projects/:id" component={ProjectPage} /> 
      </Switch> 
      </Content> 
     </Wrapper> 
    ) 
    } 
    } 
} 

const enhance = connect(
    (state, props) => ({ 
    active: props.match, 
    loading: projectSelectors.loading(state), 
    projects: projectSelectors.projects(state) 
    }), 
    { 
    fetchProjectsRequest 
    } 
) 

export default withRouter(enhance(ProjectsPage)) 

Das Problem ist, dass der console.log Ausgang in meiner render Methode ist {"path":"/projects","url":"/projects","isExact":false,"params":{}} obwohl die URL http://localhost:3000/projects/14 ist .

Ich möchte eine ID Prop zu meiner ProjectList hinzufügen, um das aktuell ausgewählte Projekt hervorzuheben.

Ich könnte die ID des Projekts in einem Geschäft in meiner ProjectPage Komponente speichern, aber ich denke, das wäre ein wenig verwirrend, vor allem, weil die URL die Informationen tatsächlich hat - also warum sollte ich etwas in den Laden schreiben?

Weitere (schlecht?) Ansatz wäre, die Lage zu analysieren Objekt der die ID von mir, aber ich denke, es gibt eine react-router/react-router-redux Art und Weise ist es, die params an dieser Stelle zu bekommen, die ich übersehen habe.

Antwort

3

@Kyle erklärt Problem sehr gut aus technischer Sicht. Ich werde nur auf die Lösung für dieses Problem konzentrieren.

Sie können matchPath verwenden, um id des ausgewählten Projekts zu erhalten.

matchPath-https://reacttraining.com/react-router/web/api/matchPath

Auf diese Weise können Sie die gleiche passende Code verwenden, außer außerhalb des normalen Zyklus verwendet machen, wie Daten aufzusammeln Abhängigkeiten, bevor auf dem Server zu machen.

Die Verwendung in diesem Fall ist sehr geradlinig.

1 Verwenden matchPath

// history is one of the props passed by react-router to component 
// @link https://reacttraining.com/react-router/web/api/history 

const match = matchPath(history.location.pathname, { 
    // You can share this string as a constant if you want 
    path: "/articles/:id" 
}); 

let articleId; 

// match can be null 
if (match && match.params.id) { 
    articleId = match.params.id; 
} 

2 Verwenden articleId in machen

{articleId && (
    <h1>You selected article with id: {articleId}</h1> 
)} 

Ich baue eine einfache Demo, die Sie verwenden können, die gleiche Funktionalität in Ihrem Projekt zu implementieren.

Demo:https://codesandbox.io/s/pQo6YMZop

Ich denke, dass diese Lösung sehr elegant ist, weil wir offiziellen react-router API verwenden, die auch für die Pfadanpassung im Router verwendet wird. Wir verwenden auch nicht window.location hier, so dass Testen/Mocking einfach sein wird, wenn Sie auch rohe Komponente exportieren.

+0

Das ist großartig! Das ist, was ich gesucht habe :-) Im Moment benutze ich 'router-parser', aber eine Methode aus dem 'react-router'-Paket ist absolut sinnvoll. Tatsächlich verwende ich bereits Konstanten für die Route :-) – Slevin

1

TLDR

Router Reagieren match.params wird ein leeres Objekt, wenn Ihr <Route />path Eigenschaft nicht enthalten :params sein.

Diesen Anwendungsfall lösen: Sie könnten let id = window.location.pathname.split("/").pop(); in der Komponente Ihrer übergeordneten Route verwenden, um die ID zu erhalten.

Detaillierte Grund, warum nicht

Wenn die path prop zu einem <Route /> geliefert keine params haben, wie /:id, reagieren Router nicht gehen für Sie die Analyse zu tun. Wenn Sie in Zeile 56 nach matchPath.js suchen, können Sie sehen, wie die Stütze match aufgebaut ist.

return { 
    path: path, // the path pattern used to match 
    url: path === '/' && url === '' ? '/' : url, // the matched portion of the URL 
    isExact: isExact, // whether or not we matched exactly 
    params: keys.reduce(function (memo, key, index) { 
     memo[key.name] = values[index]; 
     return memo; 
    }, {}) 
}; 

Dann können wir in Zeile # 43 sehen Sie können sehen, dass keys von _compilePath.keys kommt. Wir können dann die compilePath Funktion betrachten und sehen, dass sie pathToRegexp() verwendet, die stringToRegexp() verwenden wird, die tokensToRegExp() verwenden wird, die dann keys in Zeile # 355 mit keys.push(token) mutieren wird. Mit einer <Route />, die keine Params Wert in seiner path prop, die parse() Funktion in stringToRegexp() verwendet keine Token zurück und Zeile # 355 wird nicht einmal erreicht werden, da das einzige Token-Array keine Token-Objekte enthalten wird.

Also .... wenn Ihr <Route /> nicht :params hat, dann wird der Schlüssel Wert ein leeres Array sein und Sie werden keine Parameter auf match haben.

Zusammenfassend sieht es so aus, als ob Sie die Params selbst holen müssen, wenn Ihre Route sie nicht berücksichtigt. Sie könnten dazu let id = window.location.pathname.split("/").pop() verwenden.

Verwandte Themen