文章目录
React Router 从版本3到版本4是一次重大的架构革新,几乎可以视为完全不同的路由库。本文将深入探讨这两个版本之间的关键差异、新增特性以及迁移策略,帮助开发者全面理解这次重大升级。
一、概述:颠覆性的改变
React Router 4(以下简称RR4)相比React Router 3(以下简称RR3)进行了彻底的重构,主要变化可以概括为:
- 从配置中心化到组件分散化:RR3使用集中式路由配置,而RR4采用组件式路由
- 动态路由替代静态路由:RR4的路由是动态的,完全融入React的生命周期
- 更贴近React的哲学:"Just Components"的设计理念
二、核心架构差异
2.1 路由定义方式的改变
React Router 3(静态配置):
// 集中式路由配置
const routes = (
<Route path="/" component={App}>
<IndexRoute component={Home}/>
<Route path="about" component={About}/>
<Route path="users" component={Users}>
<Route path="/user/:userId" component={User}/>
</Route>
</Route>
);
// 使用方式
ReactDOM.render(
<Router history={browserHistory} routes={routes} />,
document.getElementById('root')
);
React Router 4(组件式):
// 路由作为组件分散在各处
const App = () => (
<div>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/users" component={Users}/>
</Switch>
</div>
);
const Users = () => (
<div>
<Route path="/users/:userId" component={User}/>
</div>
);
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
2.2 架构对比图
三、主要新增特性
3.1 <Switch>
组件
RR4引入了<Switch>
组件,它只会渲染第一个匹配的路由:
<Switch>
<Route path="/about" component={About}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/> {/* 404页面 */}
</Switch>
这与RR3中的<Route>
的独占性行为类似,但更加灵活。
3.2 动态路由
RR4最大的变革是引入了动态路由的概念,路由现在是组件的一部分,可以随时渲染:
// 在任意组件中都可以定义子路由
const Dashboard = ({ match }) => (
<div>
<Route path={`${match.path}/profile`} component={Profile}/>
<Route path={`${match.path}/settings`} component={Settings}/>
</div>
);
3.3 路由渲染方式多样化
RR4提供了三种路由渲染方式:
- component:直接指定组件
- render:内联函数渲染
- children:无论匹配与否都会渲染
<Route path="/home" component={Home} />
<Route path="/about" render={() => <About extra={someProp} />} />
<Route path="/contact" children={({ match }) => (
match ? <Contact/> : <EmptyContact/>
)} />
3.4 自动路由参数传递
RR4会自动将match
、location
和history
作为props传递给路由组件:
const User = ({ match, location, history }) => {
// match.params 包含路由参数
// location 包含查询字符串等信息
// history 提供导航方法
return <div>User ID: {match.params.id}</div>;
};
3.5 新增<Redirect>
组件
RR4提供了专门的<Redirect>
组件来处理重定向:
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/login" component={Login}/>
<Redirect from="/old-path" to="/new-path"/>
<Route component={NotFound}/>
</Switch>
3.6 代码分割与动态导入
RR4更好地支持代码分割和动态导入:
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Suspense>
</Router>
);
四、API变化详解
4.1 被移除或替换的API
RR3 API | RR4 替代方案 | 说明 |
---|---|---|
onEnter | 组件生命周期/高阶组件 | 使用组件DidMount等替代 |
onLeave | 组件生命周期 | 使用组件WillUnmount等替代 |
IndexRoute | <Route exact> | 使用exact属性标记精确匹配 |
Redirect | <Redirect> | 现在是组件而非配置项 |
router | withRouter | 通过高阶组件访问路由对象 |
4.2 新增API
新API | 说明 |
---|---|
<Switch> | 只渲染第一个匹配的路由 |
<Redirect> | 以组件形式实现重定向 |
<Prompt> | 导航离开前提示用户 |
withRouter | 高阶组件,使任何组件都能访问路由props |
matchPath | 工具函数,用于手动匹配路径 |
generatePath | 工具函数,根据路径模式和参数生成URL |
五、迁移策略与示例
5.1 从RR3迁移到RR4的步骤
-
替换Router包装:
// RR3 <Router history={browserHistory}> {routes} </Router> // RR4 <BrowserRouter> <App /> </BrowserRouter>
-
转换路由配置:
// RR3的集中式配置 const routes = ( <Route path="/" component={App}> <IndexRoute component={Home}/> <Route path="about" component={About}/> </Route> ); // RR4的组件式配置 const App = () => ( <div> <Switch> <Route exact path="/" component={Home}/> <Route path="/about" component={About}/> </Switch> </div> );
-
处理onEnter/onLeave:
// RR3 <Route path="dashboard" component={Dashboard} onEnter={checkAuth} onLeave={saveProgress} /> // RR4 - 使用高阶组件或组件生命周期 const AuthDashboard = checkAuth(Dashboard); class Dashboard extends React.Component { componentWillUnmount() { saveProgress(); } render() { return <div>Dashboard Content</div>; } }
5.2 常见问题解决方案
-
嵌套路由处理:
// RR3 <Route path="users" component={Users}> <Route path=":id" component={User}/> </Route> // RR4 const Users = ({ match }) => ( <div> <Route path={`${match.path}/:id`} component={User}/> </div> );
-
查询参数处理:
// RR3 // 通过this.props.location.query获取 // RR4 // 需要手动解析或使用第三方库如query-string import queryString from 'query-string'; const Users = ({ location }) => { const params = queryString.parse(location.search); return <div>Sort by: {params.sort}</div>; };
六、设计哲学变化
6.1 "Just Components"理念
RR4将路由完全视为React组件,这种设计带来了几个优势:
- 更好的组合性:路由可以像普通组件一样组合使用
- 更直观的嵌套:嵌套路由就是嵌套组件
- 动态路由:可以根据props或state条件渲染路由
6.2 动态路由 vs 静态路由
特性 | 静态路由(RR3) | 动态路由(RR4) |
---|---|---|
路由定义时机 | 应用启动时 | 渲染时 |
路由配置位置 | 集中配置 | 分散在各组件中 |
路由更新方式 | 需要重新加载配置 | 随组件更新自动变化 |
生命周期 | 独立于组件生命周期 | 完全融入组件生命周期 |
七、性能优化改进
RR4在性能方面做了许多改进:
- 更精细的更新:只有匹配的路由才会重新渲染
- 减少不必要的比较:优化了路径匹配算法
- 更好的内存管理:路由信息不再全局存储
// 性能优化示例:避免内联函数
// 不推荐 - 每次渲染都会创建新函数
<Route path="/about" render={() => <About extra={data} />} />
// 推荐 - 使用稳定的children
<Route path="/about" children={<About extra={data} />} />
八、社区生态变化
RR4的发布带来了相关生态的变化:
- react-router-dom:用于Web应用
- react-router-native:用于React Native
- react-router-redux:不再推荐使用,推荐使用connected-react-router
九、总结与建议
React Router 4是一次革命性的升级,它:
- 更符合React的组件化思想
- 提供了更大的灵活性和动态性
- 简化了许多复杂场景的实现
- 需要开发者转变思维方式
迁移建议:
- 新项目直接使用RR4或更高版本
- 大型现有项目逐步迁移,可以同时使用两个版本
- 充分利用动态路由特性构建更灵活的应用架构
- 学习RR4的新模式需要时间,但长期来看会提高开发效率
React Router的这次变革代表了前端路由向更组件化、更动态化方向的发展趋势,理解这些变化有助于我们构建更现代化的React应用。