Yutt's Blog

React Router

2018/04/24 Share

基本使用方式

设计路由结构(嵌套和路由参数):

  • Home
  • About
  • Topic
    • Rendering
    • Component
    • Prop v state
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import React from 'react'
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'

const BasicExample = () => (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>

<hr />

<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
)

const Home = () => (
<div>
<h2>Home</h2>
</div>
)

const About = () => (
<div>
<h2>About</h2>
</div>
)

const Topics = ({ match }) => (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/rendering`}>Rendering</Link>
</li>
<li>
<Link to={`${match.url}/components`}>Component</Link>
</li>
<li>
<Link to={`${match.url}/props-v-state`}>Props v state</Link>
</li>
</ul>

<Route path={`${match.url}/:topicId`} component={Topic} />
<Route
exact
path={match.url}
render={() => <h3>Please select a toipic</h3>}
/>
</div>
)

const Topic = ({ match }) => (
<div>
<h3>{match.params.topicId}</h3>
</div>
)

export default BasicExample

重定向

以用户登陆为例,主要通过自定义路由,重定向来完成登陆功能。

主界面, public为公共界面,不登陆也能浏览,Proteted界面只有登陆了之后才能进入,否则会显示登陆提示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const AuthExample = () => (
<Router>
<div>
<AuthButton />
<ul>
<li>
<Link to="/public">Public Page</Link>
</li>
<li>
<Link to="/protected">Protected Page</Link>
</li>
</ul>
<Route path="/public" component={Public} />
<Route path="/login" component={Login} />
<PrivateRoute path="/protected" component={Protected} />
</div>
</Router>
)

登陆标志,以及登陆和退出的方法,这里用定时器来模拟异步。

1
2
3
4
5
6
7
8
9
10
11
const fakeAuth = {
isAuthenticated: false,
authenticate(cb) {
this.isAuthenticated = true
setTimeout(cb, 100)
},
signout(cb) {
this.isAuthenticated = false
setTimeout(cb, 100)
},
}

退出按钮,由于登陆成功后,需要重新回到主页,因此可以使用withRouter高阶组件,通过该组件,可以在任何地方访问打history对象。我们可以将路由想象成一个栈的存储结构,通过push方法,可以替换当前栈中的条目,这个方法可以解决用户退出后,使用浏览器后退按钮时,依然可以进入被保护的页面的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const AuthButton = withRouter(
({ history }) =>
fakeAuth.isAuthenticated ? (
<p>
Welcome!{' '}
<button
onClick={() => {
fakeAuth.signout(() => history.push('/'))
}}
>
Sign out
</button>
</p>
) : (
<p>You are not logged in.</p>
),
)

自定义路由,本质是对Route组件的包装。由于protected具有权限性,只有登陆的用户才能查看,而没有登陆的用户会重定向到登陆界面,所以需要通过自定义路由来对该页面进行权限判定。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: '/login',
state: { from: props.location },
}}
/>
)
}
/>
)

Login组件有一个需要注意的地方,一般地,为了提高用户的体验度,登陆成功之后,需要重定向回到登陆之前的界面,例如我们是从protected界面进入login界面的,则重定向至protected界面,而不是跳转至其它界面。通过location.state.from能看到是从哪个界面进入界面的,也就是字面意思的,来自哪个界面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const Public = () => <h3>Public</h3>

const Protected = () => <h3>Protected</h3>

class Login extends React.Component {
state = {
redirectToReferrer: false,
}

login = () => {
fakeAuth.authenticate(() => {
this.setState({ redirectToReferrer: true })
})
}

render() {
const { from } = this.props.location.state || { from: { pathname: '/' } }
const { redirectToReferrer } = this.state

if (redirectToReferrer) {
return <Redirect to={from} />
}

return (
<div>
<p>You must log in to view the page at {from.pathname}</p>
<button onClick={this.login}>Log in</button>
</div>
)
}
}

Switch(构建404页面的路由)

需要解决的问题: 一个组件下有多个route,而我们只要去匹配到其中一个route,如果匹配成功,则只显示该route的内容,而不需要继续往下判断。在这个例子中我们会构造许多链接,如果该链接的路由不存在,那么会自动进入404页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const NoMatchExample = () => (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/old-match">Old Match, to be redirected</Link>
</li>
<li>
<Link to="/will-match">Will Match</Link>
</li>
<li>
<Link to="/will-not-match">Will Not Match</Link>
</li>
<li>
<Link to="/also/will/not/match">Also Will Not Match</Link>
</li>
</ul>
<Switch>
<Route path="/" exact component={Home} />
<Redirect from="/old-match" to="/will-match" />
<Route path="/will-match" component={WillMatch} />
<Route component={NoMatch} />
</Switch>
</div>
</Router>
);
CATALOG
  1. 1. 基本使用方式
  2. 2. 重定向
  3. 3. Switch(构建404页面的路由)