GVKun编程网logo

React Router v4呈现多个路由(react 多级路由)

10

在本文中,我们将给您介绍关于ReactRouterv4呈现多个路由的详细内容,并且为您解答react多级路由的相关问题,此外,我们还将为您提供关于ReactRouter4嵌套路由未呈现、ReactRo

在本文中,我们将给您介绍关于React Router v4呈现多个路由的详细内容,并且为您解答react 多级路由的相关问题,此外,我们还将为您提供关于React Router 4嵌套路由未呈现、React Router v4 & v5 拦截器(钩子)、静态路由、route-view 实现、React Router v4 - 如何获取当前路由?、React Router V4 正式版发布,React 路由解决方案的知识。

本文目录一览:

React Router v4呈现多个路由(react 多级路由)

React Router v4呈现多个路由(react 多级路由)

我正在创建SPA,并尝试使用react-router-dom软件包版本在应用程序中设置“路由” 4.1.1

我的路线定义如下:

<BrowserRouter>  <div>    <Route exact path="/" component={Login} />    <Route path="/login" component={Login} />    <Route path="404" component={NotFound} />    <Route path="*" component={NotFound} />  </div></BrowserRouter>

基本上,我想设置路由,以便对未定义路由的页面的任何请求都转到{NotFound}组件。

如何做到这一点?上面的解决方案在请求页面时同时呈现LoginNotFound组件/login

亲切的问候

答案1

小编典典

这是官方教程中的示例,如何避免呈现多条路线

import { Switch, Route } from ''react-router    <Switch>      <Route exact path="/" component={Home}/>      <Route path="/about" component={About}/>      <Route path="/:user" component={User}/>      <Route component={NoMatch}/>    </Switch>

React Router 4嵌套路由未呈现

React Router 4嵌套路由未呈现

我正在尝试在我的组件之一中进行嵌套路由。

这是父组件:

const App = () => (  <BrowserRouter>    <Provider store={store}>      <Switch>        <Route exact path="/" component={Landing} />        <Route path="/contribute" component={Contribute} />      </Switch>    </Provider>  </BrowserRouter>);

这是子组件:

const Landing = () => (  <div>    <SearchBar />    <section className="results-sctn">      <Route exact path="/" component={ArtistList} />      <Route path="/test" component={Test} />    </section>  </div>);

ArtistList可以很好地呈现/路线,但/test呈现完全空白的页面。知道为什么会这样吗?

答案1

小编典典

发生此现象的原因是exact在父路由上提到了一个属性

<Route exact path="/" component={Landing} />

因此,发生的事情是react-router看到了一条/test匹配的路径,然后尝试从顶层开始进行匹配。它看到两条路线,一条是exactly/,另一条是/contribute。它们都不符合所需的路径,因此您会看到空白页

你需要写

<Route path="/" component={Landing} />

因此,当您执行此操作时,它将看到部分/匹配的内容/test,然后尝试在要查找的landing组件中找到匹配的路由。

还更改父Route的顺序,因为Switch会渲染第一个匹配项,并且/是部分匹配项,/test因此将/contribute无法工作

您的最终代码如下所示

const App = () => (  <BrowserRouter>    <Provider store={store}>      <Switch>        <Route path="/contribute" component={Contribute} />        <Route path="/" component={Landing} />      </Switch>    </Provider>  </BrowserRouter>);

React Router v4 & v5 拦截器(钩子)、静态路由、route-view 实现

React Router v4 & v5 拦截器(钩子)、静态路由、route-view 实现

前提

React Routerv3 版本之前 是有 onEnter 钩子函数的,也支持静态路由配置;,但到了 v4 版本后钩子函数被移除,官方说是为了将此提供给开发者,由开发者自由发挥。既然如此我们就只能自己实现,目前网上有很多版本,大多都是差不多的,这里做一个总结并深化一下。同时提供钩子函数或者vue中叫路由守卫和静态化路由配置。

钩子函数实现

钩子函数实现比较简单,只需要包装一下官方的路由即可实现,这里我们允许钩子支持 Promise 异步,就需要一个异步组件;代码如下

异步组件代码

class AsyncBeforeEnter extends React.PureComponent {
    constructor(props) {
        super(props)
        this.state = {
            // 注意:此处component和render不会同时使用,同Route中component和render,render方法优先级要高
            // 目标组件 同 <Route componet>
            Component: null,
            // 目标组件render 方法  同 <Route render>
            render: null,
            // 错误信息
            error: null,
            // 标记异步是否完成
            completed: false
        }
    }
    componentDidMount() {
        const { beforeEnter, ...props } = this.props
        // beforeEnter 钩子函数
        const enter = beforeEnter({ ...props })
        if (isPromise(enter)) {
            // 判断是否是Promise
            enter
                .then(next => {
                    this.handleAfterEnter(next)
                })
                .catch(error => {
                    console.error(error)
                    this.setState({ error })
                })
        } else {
            this.handleAfterEnter(enter)
        }
    }
    handleAfterEnter(next) {
        // 结果处理
        const { route = {}, ...props } = this.props
        // 如果结果是null 或者undefined 或者 true : 不做任何处理直接渲染组件
        if (next === null || next === undefined || next === true) {
            this.completed(route.component, route.render)
            return
        }
        // 返回false:阻止组件的渲染
        if (next === false) {
            this.completed(null)
            return
        }

        // 返回 string : 跳转的路由,类似http中302状态码
        // 这里使用 React Router 的 Redirect 做跳转
        if (typeof next === ''string'') {
            this.completed(null, () => <Redirect to={next} from={props.location.pathname} />)
            return
        }
        // 返回React 组件
        if (typeof next === ''function'' || React.isValidElement(next)) {
            this.completed(null, () => next)
            return
        }

        // 返回 Object: 如果有 redirect=true 的属性,做跳转
        // 否则使用 Route 组件渲染
        if (isPlainObject(next)) {
            const { redirect, ...nextProps } = next
            if (redirect === true) {
                this.completed(null, () => <Redirect {...nextProps} {...{ from: props.location.pathname }} />)
                return
            }
            this.completed(() => <Route {...nextProps} />)
            return
        }
        warn(`"${props.location.pathname} => beforeEnter"
hook return values error. expected null? undefined? true? React.Component? HTMLElement? Route props?
route props detail to see
https://reacttraining.com/react-router/web/api/Route
https://reacttraining.com/react-router/web/api/Redirect`
        )
        // 例外情况 阻止组件的渲染
        this.completed(null)
    }
    /**
     * 完成后改变state渲染组件:
     * @param component 
     * @param render 
     */
    completed(component, render) {
        this.setState({ Component: component, render, completed: true, error: null })
    }

    getExtraProps() {
        // 去掉钩子函数,获取其他props
        const { loading: Loading, beforeEnter, ...props } = this.props
        return { ...props }
    }
    render() {
        const { Component, render, error, completed } = this.state
        if (!completed) {
            // 未完成
            return null
        }
        // 已完成
        if (render && typeof render === ''function'') {
            return render(this.getExtraProps())
        }
        return Component ? <Component {...this.getExtraProps()} /> : null
    }
}

带有钩子函数的 Route

将其命名为 PrivateRoute
export default (route) => (
    <Route
        path={route.path}
        exact={route.exact}
        strict={route.strict}
        location={route.location}
        sensitive={route.sensitive}
        children={route.children}
        render={props => {
            // beforeEnter
            const { beforeEnter, ...nextProps } = route
            // 如果有钩子函数,执行带有异步组件
            if (route.beforeEnter && typeof route.beforeEnter === ''function'') {
                return (
                    <AsyncBeforeEnter
                        beforeEnter={beforeEnter}
                        route={nextProps}
                        {...props}
                        {...extraProps}
                    />
                )

            }
            // 直接渲染
            return (
                route.render && typeof route.render ?
                    (
                        route.render({ ...props, ...extraProps, route: nextProps })
                    ) : (
                        route.component ? (
                            <route.component
                                route={nextProps}
                                {...props}
                                {...extraProps}
                            />
                        ) : null
                    )
            )
        }}
    />
)

使用的时候就可以用该 Route 代替官方的
示例:

<PrivateRoute path="/" component={Example} beforeEnter={(props) => check(props) }/>
<PrivateRoute path="/user" component={User} beforeEnter={(props) => check(props) }/>

静态化路由配置,并支持钩子函数

静态化路由配置官方页给出了方案,见:react-router-config,本文的静态路由配置也是参考了该实现,并重写了其中的实现,加入钩子函数

静态路由配置

基本的静态路由表如下

// 顶级两个路由
// 一个登录
// 其他需要授权后放回
export default [
    {
        path: ''/example'',
        key: ''example'',
        component: Example,
        beforeEnter(props) {
            if (auth(props.localtion.pathname)) {
                return true
            }
            return ''/login''
        },
        // 子路由
        routes: [
            {
                path: ''/example1'',
                key: ''example1'',
                component: Example1,
            }
        ]
    },
    {
        path: ''/login'',
        key: ''login'',
        component: Login
    }
]

改写钩子函数使其能渲染静态路由表=>renderRoutes


// renderRoutes
export default (routes, switchProps = {}, extraProps = {}) => {
    return routes && routes.length > 0 ? (
        <Switch {...switchProps}>
            {
                routes.map((route, i) => (
                    <Route
                        key={route.key || i}
                        path={route.path}
                        exact={route.exact}
                        strict={route.strict}
                        location={route.location}
                        sensitive={route.sensitive}
                        children={route.children}
                        render={props => {
                            // beforeEnter
                            const { beforeEnter, ...nextProps } = route
                            if (route.beforeEnter && typeof route.beforeEnter === ''function'') {
                                return (
                                    <AsyncBeforeEnter
                                        beforeEnter={beforeEnter}
                                        route={nextProps}
                                        {...props}
                                        {...extraProps}
                                    />
                                )

                            }
                            return (
                                route.render && typeof route.render ?
                                    (
                                        route.render({ ...props, ...extraProps, route: nextProps })
                                    ) : (
                                        route.component ? (
                                            <route.component
                                                route={nextProps}
                                                {...props}
                                                {...extraProps}
                                            />
                                        ) : null
                                    )
                            )
                        }}
                    />
                ))
            }
        </Switch>
    ) : null
}

使用就可以调用 renderRoutes 方法 , 该实例摘自官方示例:

const Root = ({ route }) => (
  <div>
    <h1>Root</h1>
    {/* child routes won''t render without this */}
    {renderRoutes(route.routes)}
  </div>
);

const Home = ({ route }) => (
  <div>
    <h2>Home</h2>
  </div>
);

const Child = ({ route }) => (
  <div>
    <h2>Child</h2>
    {/* child routes won''t render without this */}
    {renderRoutes(route.routes, { someProp: "these extra props are optional" })}
  </div>
);

const GrandChild = ({ someProp }) => (
  <div>
    <h3>Grand Child</h3>
    <div>{someProp}</div>
  </div>
);

ReactDOM.render(
  <BrowserRouter>
    {/* kick it all off with the root route */}
    {renderRoutes(routes)}
  </BrowserRouter>,
  document.getElementById("root")
);

实现类似 vue-router 里面的 route-view 功能

经过以上的处理,基本的钩子函数和静态路由就算配置完成了;功能虽然完成了,但总感觉使用上有点麻烦;确实,有没有类似 vue-router 中的 route-view 这种的一步到位的呢?好的,安排。。。
这里需要用到 React contextv16 以前这是不推荐的,不过现在已经成熟了,可以大胆的用了;如果不知道怎么用和什么原理可以 去这里 补一下知识
React Context.png

这里还有一个很关键的地方,看图划重点:
Context Provider.png

可以重复使用,内部的值会覆盖外层的值,这样我们就可以多层路由嵌套了;

创建 context

import React from ''react''

const RouteContext = React.createContext([])
// devtool 中使用
RouteContext.displayName = ''RouteViewContext''

export const RouteProvider = RouteContext.Provider
export const RouteConsumer = RouteContext.Consumer

创建 RouteView

import { RouteConsumer } from ''./context''
import renderRoutes from ''./renderRoutes''

//RouteView
export default () => {
    return (
        <RouteConsumer>
            {/* 使用静态路由渲染 */}
            {/* ruotes 由RouteProvider 提供 */}
            {routes => renderRoutes(routes)}
        </RouteConsumer>
    )
}

再次改写 renderRoutes, 使其能够渲染下级路由

import { RouteProvider } from ''./context''

// renderRoutes
export default (routes, switchProps = {}, extraProps = {}) => {
    return routes && routes.length > 0 ? (
        <Switch {...switchProps}>
            {
                routes.map((route, i) => (
                    <Route
                        key={route.key || i}
                        path={route.path}
                        exact={route.exact}
                        strict={route.strict}
                        location={route.location}
                        sensitive={route.sensitive}
                        children={route.children}
                        render={props => {
                            checkProps(props)
                            // beforeEnter
                            const { beforeEnter, ...nextProps } = route

                            // RouteProvider 提供下级路由所需的数据
                            if (route.beforeEnter && typeof route.beforeEnter === ''function'') {
                                return (
                                    <RouteProvider value={route.routes}>
                                        <AsyncBeforeEnter
                                            beforeEnter={beforeEnter}
                                            route={nextProps}
                                            {...props}
                                            {...extraProps}
                                        />
                                    </RouteProvider>
                                )

                            }
                            return (
                                <RouteProvider value={route.routes}>
                                    {
                                        route.render && typeof route.render ?
                                            (
                                                route.render({ ...props, ...extraProps, route: nextProps })
                                            ) : (
                                                route.component ? (
                                                    <route.component
                                                        route={nextProps}
                                                        {...props}
                                                        {...extraProps}
                                                    />
                                                ) : null
                                            )
                                    }
                                </RouteProvider>
                            )
                        }}
                    />
                ))
            }
        </Switch>
    ) : null
}

使用

在入口js添加代码如下

import { RouteProvider, RouteView } from ''../router''

// 静态路由
const routes = [
    // 略。。。
]
class App extends React.PureComponent {
    // 略。。。
    render() {

        return (
            // 略。。。
            // 提供顶层路由即可
            // 下级路由 renderRoutes 处理
            <RouteProvider value={routes}>
                <RouteView />
            </RouteProvider>
            // 略。。。
        )
    }
}
export default App

二级路由使用

class Example extends React.PureComponent {
    // 略。。。
    render() {
        // 此处便不需要再提供routes了
        // 在 renderRoutes 已经由 RouteProvider 提供了
        return (
            <div>
                Example
                <RouteView />
            </div>
        )
    }
}
export default Example

通过以上努力,我们就具备了静态路由、钩子函数、类似 vue-routerrouter-view
最终的努力的结果:

  • 方便鉴权
  • 路由方便管理
  • 多层级路由一个组件即可实现渲染

原文出处:React Router v4 & v5 拦截器(钩子)、静态路由、route-view 实现

参考文章

  • https://reacttraining.com/react-router/web/guides/quick-start
  • https://github.com/ReactTraining/react-router/tree/master/packages/react-router-config
  • https://github.com/mirrorjs/mirror/issues/78
  • https://stackoverflow.com/questions/50928349/react-router-4-how-to-wait-for-a-promise-to-resolve-inside-render-method-of-ro
  • https://juejin.im/post/5d2d32a9f265da1b8b2b90c7
  • https://zh-hans.reactjs.org/docs/context.html

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

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

我想显示一个title<AppBar />某种方式从当前路由传入的 in。

在 React Router v4 中,如何将<AppBar />当前路由传递到它的titleprop 中?

  <Router basename=''/app''>    <main>      <Menu active={menu} close={this.closeMenu} />      <Overlay active={menu} onClick={this.closeMenu} />      <AppBar handleMenuIcon={this.handleMenuIcon} title=''Test'' />      <Route path=''/customers'' component={Customers} />    </main>  </Router>

prop有没有办法从自定义传递自定义标题<Route />

答案1

小编典典

在 react-router 的 5.1 版本中有一个叫做 useLocation 的钩子,它返回当前的位置对象。这在您需要知道当前 URL
的任何时候都可能有用。

import { useLocation } from ''react-router-dom''function HeaderView() {  const location = useLocation();  console.log(location.pathname);  return <span>Path : {location.pathname}</span>}

React Router V4 正式版发布,React 路由解决方案

React Router V4 正式版发布,React 路由解决方案

React Router V4 正式版发布,该版本相较于前面三个版本有根本性变化,遵循 Just Component 的 API 设计理念。

本次升级的主要变更有:

  • 声明式 Declarative

  • 可组合 Composability

本次升级 React Router V4 吸取了 React 的理念:所有的东西都是 Component。因此 升级之后的 Route、Link、Switch……等都是一个普通的组件。

React Router V4 基于 Lerna 管理多个 Repository。在此代码库包括:

  • react-router React Router 核心

  • react-router-dom 用于 DOM 绑定的 React Router

  • react-router-native 用于 React Native 的 React Router

  • react-router-redux React Router 和 Redux 的集成

  • react-router-config 静态路由配置帮助助手

React Router V4 中文文档

今天的关于React Router v4呈现多个路由react 多级路由的分享已经结束,谢谢您的关注,如果想了解更多关于React Router 4嵌套路由未呈现、React Router v4 & v5 拦截器(钩子)、静态路由、route-view 实现、React Router v4 - 如何获取当前路由?、React Router V4 正式版发布,React 路由解决方案的相关知识,请在本站进行查询。

本文标签: