如何在父路由组件中获取参数

IT技术 reactjs react-router react-redux
2021-05-10 04:05:39

我正在使用 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

我想向IDmy添加一个propsProjectList以突出显示当前选定的项目。

我可以将项目的 ID 保存在我的ProjectPage组件内的 store 中,但我认为这会有点混乱,尤其是因为 URL 实际上包含信息——那么我为什么要在 store 中写一些东西呢?

另一种(不好?)方法是解析位置对象并自己获取 ID,但我认为此时有一种react-router/react-router-redux方法可以获取我忽略的参数。

2个回答

@Kyle 从技术角度很好地解释了问题。我只会专注于解决这个问题。

您可以使用matchPath来获取id选定的项目。

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

这使您可以使用在正常渲染周期之外使用的相同匹配代码,例如在服务器上渲染之前收集数据依赖项。

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

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;
}

2articleId在渲染中使用

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

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

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

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

TLDR

match.params如果您的<Route /> path属性不包含.React router将是一个空对象:params

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

详细原因不

如果path提供给 aprop<Route />没有任何参数,例如/:id,react router 不会为您进行解析。如果您查看matchPath.js第 56 行,您可以开始了解matchprops的构造方式。

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;
  }, {})
};

然后我们可以看看第 43 行,你可以看到它keys来自_compilePath.keys. 然后我们可以查看该compilePath函数,并看到它使用pathToRegexp(),将使用stringToRegexp(),将使用tokensToRegExp(),然后将keys在#355 行上使用进行变异keys.push(token)如果 a<Route />在其pathprop 中没有 params 值,则parse()使用函数stringToRegexp()将不会返回任何标记,甚至不会到达第 355 行,因为唯一的标记数组将不包含任何标记对象。

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

总之,如果您的路线没有考虑到这些参数,您似乎将不得不自己获取这些参数。你可以通过使用let id = window.location.pathname.split("/").pop().