1、与 v3 的差异
v3 的特点:
- 路由配置集中在一个地方
- 布局和页面嵌套是由<Route>组件的嵌套派生而来的
v4 的特点: - 不提倡将路由配置集中,而是分散化
- Route直接参与布局和页面嵌套
- Route本身就是组件
- Route 代替 props.children 实现嵌套
2、V4 的一些特性
- 包容路由(Inclusive Routing)
<Route path="/" component={HomePage} />
<Route path="/users" component={UsersPage} />
当访问/users,HomePage 和 UserPage 都会被渲染
- 独占路由(Exclusive Routing)
可以使用switch组件来实现v3式的独占路由,为了避免包容路由的规则,仍需使用exact
const PrimaryLayout = () => (
<div className="primary-layout">
<PrimaryHeader />
<main>
<Switch>
<Route path="/" exact component={HomePage} /> // 使用exact来精准匹配
<Route path="/users/add" component={UserAddPage} /> // /users/add 放在 /users前面就可以避免对/users使用exact
<Route path="/users" component={UsersPage} /> // /users 放在 /users/add后面就可以避免对/users使用exact
<Redirect to="/" /> // 都不匹配时,走 redirect
</Switch>
</main>
</div>
)
3、一些技巧
- 嵌套
子路由中用this.props.match.path来获取父路由的匹配规则
<Switch>
<Route path={props.match.path} exact component={BrowseUsersPage} />
<Route path={`${props.match.path}/:userId`} component={UserProfilePage} />
</Switch>
- 指定参数类型(/:userId(\d+))
<Route path={`/users/:userId(\\d+)`} component={UserProfilePage} /> // /users/edit 不会匹配,/users/123才会匹配
- <Link> & <NavLink>
功能一样,只是navlink组件可更加方便定制激活时的样式 - match & history 常用属性
match.params.XX
match.path // 用于嵌套 Routes
match.url // 用于嵌套 Links
history.push - URL Query Strings
v4里不能直接获取类似hash或者query string这样的参数,可以使用这个三方库 query-string
// 1、取查询字符串
const parsed = queryString.parse(location.search); // location.search='?foo=bar'
console.log(parsed); // {foo: 'bar'}
// 2、取hash
const parsedHash = queryString.parse(location.hash); // location.hash = '#token=bada55cafe'
console.log(parsedHash); // {token: 'bada55cafe'}
// 3、制作location.search
parsed.foo = 'unicorn';
parsed.ilike = 'pizza';
const stringified = queryString.stringify(parsed); // 'foo=unicorn&ilike=pizza'
location.search = stringified;
// note that `location.search` automatically prepends a question mark
console.log(location.search); // '?foo=unicorn&ilike=pizza'
- 布局上
当应用里有登录这种逻辑时,最好将登录和主应用分离,将其作为两个顶级路由
class App extends React.Component {
render() {
return (
<Provider store={store}>
<BrowserRouter>
<Switch>
<Route path="/auth" component={UnauthorizedLayout} />
<AuthorizedRoute path="/app" component={PrimaryLayout} />
</Switch>
</BrowserRouter>
</Provider>
)
}
}
class AuthorizedRoute extends React.Component {
componentWillMount() {
getLoggedUser()
}
render() {
const { component: Component, pending, logged, ...rest } = this.props
return (
<Route {...rest} render={props => {
if (pending) return <div>Loading...</div>
return logged
? <Component {...this.props} />
: <Redirect to="/auth/login" />
}} />
)
}
}
const stateToProps = ({ loggedUserState }) => ({
pending: loggedUserState.pending,
logged: loggedUserState.logged
})
export default connect(stateToProps)(AuthorizedRoute)
- 组件命名
顶级组件以 Layout结尾,页面级组件以 Page 结尾 - Route的三种渲染方式
component // 本质调用React.createElement 创建Component
render // 适用于要封装高阶组件的情形,如封装一个<FadingRoute>
// wrapping/composing
const FadingRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
<FadeIn>
<Component {...props}/>
</FadeIn>
)}/>
)
<FadingRoute path="/cool" component={Something}/>
children // 不管路径是否匹配,总是渲染。只是当路径不匹配时,match为null
<ul>
<ListItemLink to="/somewhere"/>
<ListItemLink to="/somewhere-else"/>
</ul>
const ListItemLink = ({ to, ...rest }) => (
<Route path={to} children={({ match }) => (
<li className={match ? 'active' : ''}>
<Link to={to} {...rest}/>
</li>
)}/>
)
网友评论