一个问题?
在 React 单页应用中,相信大家都会用到 react-router-dom 这个库,用来做路由管理,然而最后是不是都会写成下面这样呢?
<Switch>
<Route path="/login" exact component={LoginPage} />
<Route path="/notfound" exact component={NotFound} />
<Route path="/notauth" exact component={NotAuth} />
<Route path="/version/:collection/:book/:page/:version" exact component={VersionPage} />
<Route path="/collection/:collection/books" exact breadcrumbName="" component={SpacePage} />
<Route path="/collection/:collection/settings" exact breadcrumbName="" component={SettingPage} />
<Route path="/collection/:collection/teams" exact breadcrumbName="" component={TeamsPage} />
<Route path="/collection/:collection/recently" exact breadcrumbName="" component={RecentlyPage} />
<Route path="/book/:id" exact component={BookLayout} />
<Redirect from="/" exact to={DefaultFront} />
<Redirect to="/notfound" />
</Switch>
所有的路由都写在一个文件里?随着路由越来越多,这个文件会越来越大。而且跳转页面是直接使用路径字符串,如 history.push('/login')
,一旦我们想要修改一个页面的路径,就要在所有引用了这个路径的代码中修改。
有洁癖的同学应该和我感受相同,会觉得这真的 不 够 优 雅。那么可以怎样改善呢❓❓❓
第一步:将路径统一管理
第一步,我们可以将所有路径字符串统一管理。
// router/path.ts
// 不同模块的路径前缀
const pathPrefix = {
apply: '/application',
intro: '/intro',
console: '/console'
};
const paths = {
login: '/login',
home: '/',
applyContainerInstance: pathPrefix.apply + '/container/instance',
applyStorageFile: pathPrefix.apply + '/storage/file',
introContainerInstance: pathPrefix.intro + '/container/instance',
introStorageFile: pathPrefix.intro + '/storage/file',
introDatabaseMySQL: pathPrefix.intro + '/database/mysql',
consoleOverview: pathPrefix.console + '/overview',
consoleInstance: pathPrefix.console + '/instance',
consoleInstanceDetail: pathPrefix.console + '/instance/detail',
consoleSG: pathPrefix.console + '/securityGroup',
consoleSGCreate: pathPrefix.console + '/securityGroup/create',
consoleSGDetail: pathPrefix.console + '/securityGroup/detail',
consoleDockerAuth: pathPrefix.console + '/dockerAuth',
consoleProjectMember: pathPrefix.console + '/projectMember'
};
export { pathPrefix, paths };
如上所示,我们将所有路径都统一写在 router/path.ts 文件中,并将它导出。这样,外部需要跳转某个页面时,写法就变成了这样:
import { paths } from '@/router/paths.ts'
//...
history.push(paths.login)
这样不仅显得清晰,而且如果我们想要改变路径名称,只需在 path.ts 中修改即可。
然而,这样也会存在一个问题,如果是 /project/:projectId
这样带有动态 id 的路径怎么办呢?这样的路径可以做路由匹配,可是不能直接用来跳转呀!不急,方法有两种。
-
替换
import { paths } from '@/router/paths.ts' //... const projectPagePath = paths.project.replace(':projectId','1'); history.push(projectPagePath)
-
使用 query
除了
/project/:projectId
这种路径,我们也可以使用/project?projectId=1
来携带动态 id。import { paths } from '@/router/paths.ts' //... history.push(`paths.project?projectId=${1}`)
第二步:分模块
前端页面往往是分模块的,这些模块路径的前缀都相同。举个例子,介绍页面 “/introduction/xxx”,管理页面“/admin/xxx”。我们可以把一个模块的路由单独维护在一个文件中,这样路由代码会更为清晰。
// router/index.tsx
const SwitchRouterComponent = () => {
return (
<Suspense fallback={<PageLoading />}>
<Switch>
<Route exact path={paths.login} component={Login} />
<Route exact path={paths.home} component={Home} />
<Route>
<PageContainer>
<Switch>
{/* 前面导出路径时同时导出了路径前缀,是为了在这里使用,用来匹配一个模块 */}
<Route path={pathPrefix.apply} component={Application} /> {/* application 模块 */}
<Route path={pathPrefix.intro} component={Intro} /> {/* introduction 模块 */}
<Route path={pathPrefix.console} component={Console} /> {/* console 模块 */}
<Route path="*" component={NotFound} />
</Switch>
</PageContainer>
</Route>
</Switch>
</Suspense>
);
};
模块路由的代码如下:
// router/intro.tsx
// introduction 模块
const Intro = () => {
return (
<Switch>
<Route exact path={paths.introContainerInstance} component={Instance} />
<Route exact path={paths.introStorageFile} component={File} />
<Route exact path={paths.introDatabaseMySQL} component={Database} />
<Redirect to={paths.introContainerInstance} />
</Switch>
);
};
把不同模块的路由维护在不同文件中,这样管理起来就方便多了,而且不用将所有路由都堆在一个文件中。
总结
对于大的后台管理项目,我觉得这样去管理路由路径还是很有必要的,方便修改,而且不会显得乱!!然而对于小项目,页面数量很少,就没有这样做的必要了~
最后,如果大家有什么其他好的做法,欢迎评论交流~😺