react-router 还是 react-router-dom?
在 React 的使用中,我们一般要引入两个包,react 和 react-dom,那么 react-router 和react-router-dom 是不是两个都要引用呢?
非也,坑就在这里。他们两个只要引用一个就行了,不同之处就是后者比前者多出了 <Link> <BrowserRouter> 这样的 DOM 类组件。因此我们只需引用 react-router-dom 这个包就行了
react-router
: 实现了路由的核心功能
react-router-dom
: 基于react-router
,加入了在浏览器运行环境下的一些功能,例如:Link
组件,会渲染一个a
标签,Link组件源码a
标签行; BrowserRouter
和HashRouter
组件,前者使用pushState
和popState
事件构建路由,后者使用window.location.hash
和hashchange
事件构建路由。
react-router-dom依赖react-router,所以我们使用npm安装依赖的时候,只需要安装相应环境下的库即可,不用再显式安装react-router。基于浏览器环境的开发,只需要安装react-router-dom;npm会自动解析react-router-dom包中package.json的依赖并安装。
react-router-dom中package.json依赖:
"dependencies": {
"history": "^4.7.2",
"invariant": "^2.2.2",
"loose-envify": "^1.3.1",
"prop-types": "^15.5.4",
"react-router": "^4.2.0",
"warning": "^3.0.0"
}
React-Router4.0不允许出现嵌套的子路由
例如:
<Router>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
</Route>
</Router>
React-Router4.0主张将路由拆分出来,不直接使用嵌套路由
源文件改为
<BrowserRouter>
<Route path="/" component={App}></Route>
</BrowserRouter>
然后在APP组件里面再次写入
<Switch>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox} />
<Switch>
只渲染第一个匹配的组件<Switch>: 一个路由可能同时匹配多个路径,在<Switch>中,只渲染匹配的第一个,其他的放弃。之前这是Router的默认行为,4.0中不默认了
在react-router 2.0中可选参数是这样写的
<Route path='/index(/:hello)' />
而在react-4.0中你会惊喜的发现这种写法没用了
要写成这样
<Route path='/index/:hello?' />
后边的问号表示这个参数是可选的
Router变化
react-router将history分为三类。
- hashHistory 老版本浏览器的history
- browserHistory h5的history
- createMemoryHistory node环境下的history,存储在memory中
4.0之前版本的react-router针对三者分别实现了createHashHistory、createBrowserHistory和create MemoryHistory三个方法来创建三种情况下的history,这里就不讨论他们不同的处理方式了,好奇的可以去了解一下~
到了4.0版本,在react-router-dom中直接将这三种history作了内置,于是我们看到了BrowserRouter、HashRouter、MemoryRouter这三种Router,当然,你依然可以使用React-router中的Router,然后自己通过createHistory来创建history来传入。
Route标签
它最基本的职责就是当页面的访问地址与 Route 上的 path 匹配时,就渲染出对应的 UI 界面。
<Route> 自带三个 render method 和三个 props 。
render methods 分别是:
- <Route component>
- <Route render>
- <Route children>
每种 render method 都有不同的应用场景,同一个<Route> 应该只使用一种 render method ,大部分情况下你将使用 component 。
props 分别是:
- match
- location
- history
location对象包括:
- pathname 同window.location.pathname
- search 同window.location.search
- state 一个捆绑在这个地址上的object对象
- action PUSH, REPLACE, 或者 POP中的一个
- key 唯一ID
发现 location.query属性没有了,现在通过 'query-string' 模块进行转换获取
import queryString from 'query-string'
let query=this.query=queryString.parse(location.search);
match 对象包含了 <Route path> 如何与 URL 匹配的信息,具有以下属性:
match对象包括:
- params: object 路径参数,通过解析 URL 中的动态部分获得键值对
- isExact: bool 为 true 时,整个 URL 都需要匹配
- path: string 用来匹配的路径模式,用于创建嵌套的 <Route>
- url: string URL 匹配的部分,用于嵌套的 <Link>
存: this.props.history.push({pathname:"/web/updateStaff/" + text.userId});
读:this.props.match.params.userId
想了解更详细的参数传递,可以参考 https://www.jianshu.com/p/ad8cc02b9e6c
BrowserRouter和HashRouter区别
hashHistory
使用 URL 中的 hash(#)部分去创建路由,举例来说,用户访问http://www.example.com/,实际会看到的是http://www.example.com/#/。
当页面刷新的时候,对于BrowserHistory, 浏览器会向后台发送整个URL的请求, 而对于HashHistory, 它只会请求后台的根目录。
browserHistory
是使用 React-Router 的应用推荐的 history方案。它使用浏览器中的 History API 用于处理 URL,创建一个像example.com/list/123这样真实的 URL 。
在browserHistory 模式下,URL 是指向真实 URL 的资源路径,当通过真实 URL 访问网站的时候,由于路径是指向服务器的真实路径,但该路径下并没有相关资源,所以用户访问的资源不存在。
当本地使用browserHistory , 因为webpack.config.js中使用 webpack-dev-server 已经做了配置。所以不会出现刷新页面404.
webpackConfig.devServer = {
contentBase: path.resolve(__dirname, 'build'),
compress: true, //gzip压缩
historyApiFallback: true,
};
但是要想在发版后正常使用,服务器需要进行相关路由配置,参考 (这里):
问题解决
1.使用render加载组件后,组件加载不出来
https://blog.csdn.net/aqtata/article/details/76169974
2.为什么用 this.props.history.push({......})不起作用
用此方法不起作用说明,你直接引用的Router路由,在ReactRouter4.x里Router里面并没有内置history对象,React Router 是建立在 history 之上的。 简而言之,一个 history 知道如何去监听浏览器地址栏的变化, 并解析这个 URL 转化为 location
对象, 然后 router 使用它匹配到路由,最后正确地渲染对应的组件。所以你只能通过createHistory创建的自定义的history对象,并将其传入Router传入来实现路由动态跳转
// HTML5 history, 推荐
import createHistory from 'history/lib/createBrowserHistory'
// Hash history
import createHistory from 'history/lib/createHashHistory'
// 内存 history (如:node环境)
import createHistory from 'history/lib/createMemoryHistory'
const history = createHistory()
......
<Router history={history }></Router>
history 一个管理js应用session会话历史的js库。它将不同环境(浏览器,node...)的变量统一成了一个简易的API来管理历史堆栈、导航、确认跳转、以及sessions间的持续状态。
3.为什么使用IndexRoute会报错
因为react-router4*已经抛弃了IndexRoute
以前
<BrowserRouter>
<Route path="/" component={Frame}>
<IndexRoute component={Home} />
<Route path="/detail" component={Detail}></Route>
</Route>
</BrowserRouter>
现在的默认路由为
<BrowserRouter>
<Frame>
<Route path="/" exact component={Home}/>
<Route path="/detail" component={Detail}></Route>
</Frame>
</BrowserRouter>