在根级别无法访问React Router v4嵌套匹配参数 [英] React Router v4 Nested match params not accessible at root level

查看:73
本文介绍了在根级别无法访问React Router v4嵌套匹配参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

https://codesandbox.io/s/rr00y9w2wm

  • Click on Topics
  • Click on Rendering with React

OR

    Topic 组件中访问
  • match.params.topicId时,它们与父 Topics 组件应与match.params.topicId相同
  • match.params.topicId should be identical from both the parent Topics component should be the same as match.params.topicId when accessed within the Topic component
    主题组件中访问
  • match.params.topicId未定义
  • 主题组件中访问
  • match.params.topicId渲染
  • match.params.topicId when accessed within the Topic component is undefined
  • match.params.topicId when accessed within the Topics component is rendering

我从此已解决的问题理解,这不一定是错误.

I understand from this closed issue that this is not necessarily a bug.

此要求在要在Mill Web应用程序中创建运行的用户中非常常见,在该应用程序中父级组件Topics需要访问 match.params.paramId 的用户,其中是与嵌套的(子)组件Topic:

This requirement is super common among users who want to create a run in the mill web application where a component Topics at a parent level needs to access the match.params.paramId where paramId is a URL param that matches a nested (child) component Topic:

const Topic = ({ match }) => (
  <div>
    <h2>Topic ID param from Topic Components</h2>
    <h3>{match.params.topicId}</h3>
  </div>
);

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <h3>{match.params.topicId || "undefined"}</h3>
    <Route path={`${match.url}/:topicId`} component={Topic} />
    ...
  </div>
);

从一般意义上讲,Topics可以是抽屉"或导航菜单"组件,而Topic可以是任何子组件,就像我正在开发的应用程序中一样.子组件具有其自己的:topicId参数,该参数具有其自己的(例如)<Route path="sections/:sectionId" component={Section} />路线/组件.

In a generic sense, Topics could be a Drawer or Navigation Menu component and Topic could be any child component, like it is in the application I'm developing. The child component has it's own :topicId param which has it's own (let's say) <Route path="sections/:sectionId" component={Section} /> Route/Component.

更痛苦的是,导航菜单不必与组件树具有一对一的关系.有时,菜单根级的项目(例如TopicsSections等)可能对应于嵌套结构(尽管Sections仅在主题下呈现,但/topics/:topicId/sections/:sectionId它具有自己的标准化列表,可供用户在导航栏中的标题 Sections 下使用. 因此,当点击 Sections 时,应突出显示 ,而不同时选中 Sections Topics .

Even more painful, the Navigation Menu needn't have a one-to-one relationship with the component tree. Sometimes the items at the root level of the menu (say Topics, Sections etc.) might correspond to a nested structure (Sections is only rendered under a Topic, /topics/:topicId/sections/:sectionId though it has its own normalized list that is available to the user under the title Sections in the Navigation Bar). Therefore, when Sections is clicked, it should be highlighted, and not both Sections and Topics.

在应用程序的根目录级别的导航栏组件中没有sectionIdsections路径时,有必要编写

With the sectionId or sections path unavailable to the Navigation Bar component which is at the Root level of the application, it becomes necessary to write hacks like this for such a commonplace use case.

我根本不是React Router的专家,因此,如果任何人都可以尝试针对此用例的合适的优雅解决方案,那么我将认为这是富有成果的努力.优雅,我的意思是

I am not an expert at all at React Router, so if anyone can venture a proper elegant solution to this use case, I would consider this to be a fruitful endeavor. And by elegant, I mean

  • 使用match而不是history.location.pathname
  • 不涉及诸如手动解析window.location.xxx
  • 之类的黑客手段
  • 不使用this.props.location.pathname
  • 不使用像path-to-regexp
  • 这样的第三方库
  • 不使用查询参数
  • Uses match and not history.location.pathname
  • Does not involve hacky approaches like manually parsing the window.location.xxx
  • Doesn't use this.props.location.pathname
  • Does not use third party libraries like path-to-regexp
  • Does not use query params

其他黑客/部分解决方案/相关问题:

Other hacks/partial solutions/related questions:

  1. React Router v4-如何获取当前路由?

React Router v4全局不匹配嵌套路线的孩子

TIA!

推荐答案

尝试利用查询参数?允许父级和子级访问当前选定的topic.不幸的是,您将需要使用模块 qs ,因为react-router-dom不会自动解析查询(反应路由器v3确实如此).

Try utilizing query parameters ? to allow the parent and child to access the current selected topic. Unfortunately, you will need to use the module qs because react-router-dom doesn't automatically parse queries (react-router v3 does).

工作示例: https://codesandbox.io/s/my1ljx40r9

URL的结构类似于连接字符串:

URL is structured like a concatenated string:

topic?topic=props-v-state

然后您将使用&添加到查询中:

Then you would add to the query with &:

/topics/topic?topic=optimization&category=pure-components&subcategory=shouldComponentUpdate

✔使用匹配项进行路由URL处理

✔ Uses match for Route URL handling

✔不使用this.props.location.pathname(使用this.props.location.search)

✔使用qs解析location.search

✔不涉及黑客手段

Topics.js

import React from "react";
import { Link, Route } from "react-router-dom";
import qs from "qs";
import Topic from "./Topic";

export default ({ match, location }) => {
  const { topic } = qs.parse(location.search, {
    ignoreQueryPrefix: true
  });

  return (
    <div>
      <h2>Topics</h2>
      <ul>
        <li>
          <Link to={`${match.url}/topic?topic=rendering`}>
            Rendering with React
          </Link>
        </li>
        <li>
          <Link to={`${match.url}/topic?topic=components`}>Components</Link>
        </li>
        <li>
          <Link to={`${match.url}/topic?topic=props-v-state`}>
            Props v. State
          </Link>
        </li>
      </ul>
      <h2>
        Topic ID param from Topic<strong>s</strong> Components
      </h2>
      <h3>{topic && topic}</h3>
      <Route
        path={`${match.url}/:topicId`}
        render={props => <Topic {...props} topic={topic} />}
      />
      <Route
        exact
        path={match.url}
        render={() => <h3>Please select a topic.</h3>}
      />
    </div>
  );
};


另一种方法是创建一个将参数存储到stateHOC,并且子级的state更改后,子级会更新其父级的state.


Another approach would be to create a HOC that stores params to state and children update the parent's state when its params have changed.

URL的结构类似于文件夹树:/topics/rendering/optimization/pure-components/shouldComponentUpdate

URL is structured like a folder tree: /topics/rendering/optimization/pure-components/shouldComponentUpdate

工作示例: https://codesandbox.io/s/9joknpm9jy

✔使用匹配项进行路由URL处理

✔ Uses match for Route URL handling

✔不使用this.props.location.pathname

✔使用lodash进行对象之间的比较

✔ Uses lodash for object to object comparison

✔不涉及黑客手段

Topics.js

import map from "lodash/map";
import React, { Fragment, Component } from "react";
import NestedRoutes from "./NestedRoutes";
import Links from "./Links";
import createPath from "./createPath";

export default class Topics extends Component {
  state = {
    params: "",
    paths: []
  };

  componentDidMount = () => {
    const urlPaths = [
      this.props.match.url,
      ":topicId",
      ":subcategory",
      ":item",
      ":lifecycles"
    ];
    this.setState({ paths: createPath(urlPaths) });
  };

  handleUrlChange = params => this.setState({ params });

  showParams = params =>
    !params
      ? null
      : map(params, name => <Fragment key={name}>{name} </Fragment>);

  render = () => (
    <div>
      <h2>Topics</h2>
      <Links match={this.props.match} />
      <h2>
        Topic ID param from Topic<strong>s</strong> Components
      </h2>
      <h3>{this.state.params && this.showParams(this.state.params)}</h3>
      <NestedRoutes
        handleUrlChange={this.handleUrlChange}
        match={this.props.match}
        paths={this.state.paths}
        showParams={this.showParams}
      />
    </div>
  );
}

NestedRoutes.js

import map from "lodash/map";
import React, { Fragment } from "react";
import { Route } from "react-router-dom";
import Topic from "./Topic";

export default ({ handleUrlChange, match, paths, showParams }) => (
  <Fragment>
    {map(paths, path => (
      <Route
        exact
        key={path}
        path={path}
        render={props => (
          <Topic
            {...props}
            handleUrlChange={handleUrlChange}
            showParams={showParams}
          />
        )}
      />
    ))}
    <Route
      exact
      path={match.url}
      render={() => <h3>Please select a topic.</h3>}
    />
  </Fragment>
);

这篇关于在根级别无法访问React Router v4嵌套匹配参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆