Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Redirect组件 #16

@andyChenAn

Description

@andyChenAn

react路由组件之Redirect组件

Redirect组件用于重定向,当我们进行某些操作时,会先让登录才能操作,如果我们操作时还没有登录,那么就会重定向到登录页面进行登录操作。

import React, { Component } from 'react';
import { BrowserRouter as Router , Route , Switch , Link , withRouter , Redirect } from 'react-router-dom';

const Public = () => <h3>Public</h3>;

const Private = () => <h3>Private</h3>;

const auth = {
    isAuth : false,
    authorize (callback) {
        this.isAuth = true;
        setTimeout(callback , 200);
    },
    unauthroize (callback) {
        this.isAuth = false;
        callback(callback , 200);
    }
}

function PrivateRoute (props) {
    const Component = props.component;
    const path = props.path;
    return (
        <Route path={path} render={
            (props) => {
                return auth.isAuth ? <Component {...props} /> : <Redirect to={{
                    pathname : '/login',
                    state : {from : props.location}
                }} />
            }
        } />
    )
}

class Login extends Component {
    constructor (props) {
        super(props);
        this.state = {
            redirectTo : false
        }
    }
    login = () => {
        auth.authorize(() => {
            this.setState({
                redirectTo : true
            })
        })
    }
    render () {
        let redirectTo = this.state.redirectTo;
        // 获取从哪里重定向过来的路径对象
        let { from } = this.props.location.state;
        if (redirectTo) {
            return <Redirect to={from} />
        }
        return (
            <div>
                <p>你还没有授权,请授权再查看</p>
                <button onClick={this.login}>授权</button>
            </div>
        )
    }
}

const Authorize = withRouter(class Authorize extends Component {
    constructor (props) {
        super(props);
    }
    loginOut = () => {
        auth.unauthroize(() => {
            this.props.history.push('/');
        })
    }
    render () {
        return (
            <div>
                {
                    auth.isAuth ? (
                        <div>
                            <div>你已经授权,可以查看需要授权的内容!</div>
                            <button onClick={this.loginOut}>退出</button>
                        </div>
                    ) : null
                }
            </div>
        )
    }
})


class App extends Component {
    render () {
        return (
            <Router>
                <div>
                    <Link to="/public">public</Link>
                    <Link to="/private">private</Link>
                    <Authorize />
                    <Route path="/public" component={Public} />
                    <Route path="/login" component={Login} />
                    <PrivateRoute path="/private" component={Private} />
                </div>
            </Router>
        )
    }
}

上面是一个组件的简单应用,当我们渲染一个组件时,该组件会导航到一个新的地址。这个新的地址会在history栈中覆盖当前的地址,就像我们在服务端重定向一样。

import React, { Component } from 'react';
import { BrowserRouter as Router , Route , Switch , Link , withRouter , Redirect } from 'react-router-dom';

const auth = {
    isLogin : false
}

const Home = () => <h2>home</h2>;
// 这里我们使用withRouter高阶函数来包装组件,不然的话,我们获取不到Router的三个属性(history , location,match)
// 当点击login按钮时,首先会将isLogin的状态变为true,然后调用history的push方法,让url跳转到'/'
// 路由地址发生改变,组件会重新渲染,并且会重定向到"/home",然后匹配到正确的组件
// 这里需要注意的是,这里的history对象和浏览器的history对象类似。
const Login = withRouter(({history}) => {
    const login = () => {
        auth.isLogin = true;
        history.push('/');
    }
    return (
        <div>
            <button onClick={() => login()}>login</button>
        </div>
    )
});
class App extends Component {
    render () {
        return (
            <Router>
                <div>
                    <Route exact path="/" render={() => (
                        auth.isLogin ? (
                            <Redirect to="/home"/>
                        ) : (
                            <Login />
                        )
                        )}/>
                    <Route path="/home" component={Home} />
                </div>
            </Router>
        )
    }
}
export default App;

上面这个例子中,如果我们把"exact"属性去掉会怎么样呢?其实当我们点击按钮进行重定向的时候会提示警告

Warning: You tried to redirect to the same route you're currently on: "/home"

这是因为当我们路由跳转到"/home"时,会同时匹配到"/"和"/home"。所以就会出现上面的警告提示,只需要在的组件上添加"exact"属性即可。

Redirect组件有以下几个属性:

  • 1、to属性
    • 这个属性可以是字符串也可以是对象,如果是字符串,那么表示的是重定向的url地址,如果是对象(location对象),那么对象的pathname属性表示的是重定向的url地址。
  • 2、from属性
    • 这个属性表示Redirect组件的路由原始值,当路由路径匹配from时,那么会重定向到to上面。如果Redirect组件上没有from属性,那么他都会匹配到当前路由的路径,这样的话,不管路由路径是哪个,都会重定向
  • 3、push属性
    • 该属性是一个布尔值,如果为true,表示把新的地址添加到访问历史记录里面作为入口,并且无法回退到前面的页面
  • 3、exact属性
    • 该属性是一个布尔值,如果为true,那么表示不能匹配路径的子路径,比如:当路径匹配"/home",就不能匹配"/home/one"。如果为false,那么就可以匹配,所以我们在使用路由的时候会添加,不然都会匹配到"/"。
  • 4、strict属性
    • 该属性是一个布尔值,如果为true,表示会匹配路径末尾的那个斜杠,比如:path为"/home/",不能匹配"/home",可以匹配"/home/",当然这个只匹配末尾的那个斜杠,如果斜杠后面还有参数,是不会受影响的,比如:path为"/home/",会匹配"/home/one"。

这个需要注意的是,如果想要保住路径末尾一定不会有斜杠,那么exact属性和strict属性两个必须为true。

import React, { Component } from 'react';
import { BrowserRouter as Router , Route , Switch , Link , withRouter , Redirect } from 'react-router-dom';

const auth = {
    isLogin : false
}

const Home = (props) => {
    console.log(props);
    return (
        <h2>home</h2>
    )
};
const Login = withRouter(({history}) => {
    const login = () => {
        auth.isLogin = true;
        history.push('/');
    }
    return (
        <div>
            <button onClick={() => login()}>login</button>
        </div>
    )
});

class App extends Component {
    render () {
        return (
            <Router>
                <div>
                    <Route exact path="/" render={(props) => {
                        return (
                            auth.isLogin ? (
                                <Redirect to={{
                                    pathname : '/home',
                                    name : 'andy',
                                    search : "?city=广州",
                                    state : {referrer : props.location}
                                }} />
                            ) : (
                                <Login />
                            )
                        )
                    }}/>
                    <Route path="/home" component={Home} />
                </div>
            </Router>
        )
    }
}
export default App;

上面的这个例子中,我们使用组件的to属性来重定向到指定的路径,这里的to属性是一个对象,该对象其实是一个location对象,除了包含location对象中的属性外,我们还可以自定义属性。这里重定向的路径都是符合path-to-regexp库标准的。

location : {
    hash: "",   // #号后面的值
    key: "f1t7fc",
    name: "andy",
    pathname: "/home",
    search: "?city=广州",  // 查询字符串
    state : {
        referrer : {
            hash: "",
            key: "uevpb4",
            pathname: "/",
            search: "",
            state: undefined
        }
    }
}

下面这个例子是一个from属性的应用的例子,当路由路径匹配到from属性的值时,会重定向到to属性的值上

import React, { Component } from 'react';
import { BrowserRouter as Router , Route , Switch , Link , withRouter , Redirect } from 'react-router-dom';

const About = (props) => {
    console.log(props);
    return (
        <div>about</div>
    )
}
const Home = () => <div>home</div>

// 如果<Redirect>组件将from属性删掉,那么不管是哪个路由路径,它都会匹配到,所以也都会重定向到to上
class App extends Component {
    render () {
        return (
            <Router>
                <div>
                    <Switch>
                        <Redirect from="/home" to="/about" />
                        <Route path="/about" component={About} />
                    </Switch>
                </div>
            </Router>
        )
    }
}

export default App;

Redirect组件综合例子

import React, { Component } from 'react';
import { BrowserRouter as Router , Route , Switch , Link , withRouter , Redirect } from 'react-router-dom';

// 这里我们调用withRouter高阶函数来将组件进行包装,主要目的是为了获取路由对象的三个属性(history , location , match)
const AddressBar = withRouter(class AddressBar extends Component {
    constructor (props) {
        super(props);
    }
    prevPage = () => {
        const { history } = this.props;
        history.goBack();
    }
    nextPage = () => {
        const { history } = this.props;
        history.goForward();
    }
    render () {
        return (
            <div>
                <button onClick={this.prevPage}>上一页</button>
                <button onClick={this.nextPage}>下一页</button>
                <div>URL : {this.props.location.pathname}</div>
            </div>
        )
    }
});

const isLogin = false;

class Nav extends Component {
    constructor (props) {
        super(props);
    }
    render () {
        return (
            <div>
                <Link className="link" to="/">Home</Link>
                <Link className="link" to="/old/123">Old</Link>
                <Link className="link" to="/new/456">New</Link>
                <Link className="link" to="/redirect/789">Redirect</Link>
                <Link className="link" to="/protected">Login</Link>
            </div>
        )
    }
}

class App extends Component {
    render () {
        return (
            <Router>
                <div>
                    <AddressBar />
                    <Nav />
                    <Route path="/" exact render={() => <h1>Home</h1>} />
                    <Switch>
                        // 当匹配from路径,那么会重定向到to路径上面
                        <Redirect from="/old/:id" to="/new/123" />
                        <Route path="/new/:id" render={({match}) => (
                            <h1>new : {match.params.id}</h1>
                        )} />
                    </Switch>
                    // push属性为true,添加新的地址作为访问历史记录的入口,这样就不能访问该路径之前的地址了
                    // push属性默认为false
                    <Route path="/redirect/:id" render={({match}) => (
                        <Redirect push to={`/new/${match.params.id}`} />
                    )} />
                    <Route path="/protected" render={() => (
                        isLogin ? <h1>Welcome</h1> : <Redirect to="/new/login" />
                    )} />
                </div>
            </Router>
        )
    }
}
export default App;

Metadata

Metadata

Assignees

No one assigned

    Labels

    reactreact相关

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions