如何在父路由组件中获取params

时间:2017-08-03 14:53:40

标签: reactjs react-router react-redux

我正在使用React,React-Router(v5)和Redux构建应用程序,并想知道如何在父路径中访问当前URL的参数。

这是我的参赛作品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>

这是我的ProjectsPage组件:

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))

问题是,虽然网址为console.log,但我render方法中的{"path":"/projects","url":"/projects","isExact":false,"params":{}}输出为http://localhost:3000/projects/14

我想在ID添加ProjectList道具以突出显示当前所选项目。

我可以在我的ProjectPage组件中的商店中保存项目的ID,但我认为这会有点混乱,特别是因为URL实际上有信息 - 所以我为什么要在店?

另一个(糟糕的?)方法是解析位置对象自己获取ID,但我认为有一种react-router / react-router-redux方法来获取这个参数被忽视了。

2 个答案:

答案 0 :(得分:10)

@Kyle从技术角度解释了问题。 我将专注于解决这个问题。

您可以使用matchPath获取所选项目的id

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

  

这使您可以使用与使用except相同的匹配代码   在正常的渲染周期之外,就像收集数据一样   在服务器上呈现之前的依赖关系。

在这种情况下的用法非常简单。

1使用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在渲染中使用articleId

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

我构建了一个简单的演示,您可以使用它在项目中实现相同的功能。

演示: https://codesandbox.io/s/pQo6YMZop

我认为这个解决方案非常优雅,因为我们使用官方react-router API,它也用于路由器中的路径匹配。我们也不在这里使用window.location,因此如果您导出原始组件,测试/模拟也会很容易。

答案 1 :(得分:2)

<强> TLDR

如果您的match.params <Route />媒体资源不包含path,则

React路由器:params将为空对象。

解决此用例:您可以在父路由的组件中使用let id = window.location.pathname.split("/").pop();来获取ID。

详细原因

如果提供给path的{​​{1}}道具没有任何参数,例如<Route />,则路由器不会为您进行解析。如果您在第56行查看/:id,就可以开始了解matchPath.js道具是如何构建的。

match

然后我们可以查看第43行,您可以看到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; }, {}) }; 来自keys。然后,我们可以查看_compilePath.keys函数并看到它使用compilePath,它将使用pathToRegexp(),它将使用stringToRegexp(),然后将tokensToRegExp()变更keys第{355行keys.push(token)。如果<Route />道具中path没有参数值,则parse()中使用的stringToRegexp()函数将不会返回任何令牌,甚至不会达到#355行因为唯一的标记数组不包含任何标记对象。

所以....如果你的<Route />没有:params,那么键值将是一个空数组,并且match上没有任何参数。

总之,如果您的路线没有考虑到它们,您似乎必须自己获得参数。你可以使用let id = window.location.pathname.split("/").pop()