【react-router-dom】通过路由配置来实现全局业务管控。如只有登陆之后才能访问各个路由

通过路由配置来实现全局业务管控。如只有登陆之后才能访问各个路由

react & react-router-dom $ mobx $ mobx-react

router.jsx 文件

关键的router文件,写主要场景逻辑
import React from 'react';
import { Route, Redirect ,withRouter } from 'react-router-dom';
import { inject, observer } from 'mobx-react';
import TopicList from '../components/topic-list/index';
import TopicDetail from '../components/topic-detail/index';
import TestApi from '../components/test/api-test';
import Homew from '../components/home/index';
import ListItems from '../components/topic-list/list-item';
import WrappedUserLogin from '../components/user-login/user-login';

/**
 *
 * @param isLogin  是否登陆,通常如果项目是react+mobx的项目,
 * isLogin基本都是通过store传入,那么需要把store注入到这个方法中。
 * 由于PrivateRoute 是一个 funcion 组件, 不是一个class 不能直使用注解注入,需要用函数的写法
 * 有特殊的注入方式,下面一个方法会讲述到
 * @param Component 使用大写是因为jsx文件的组件都是大写命名
 * @param rest 其他属性全部放在此处
 * @constructor
 */
const PrivateRoute = ({ isLogin, component: Component, ...rest }) => {
  <Route
    {...rest} // 把传入的组件属性全部解构出来
    render={
      props => (
        isLogin ?
          <Component {...props} /> :
          <Redirect
            to={{
              pathname: '/user/login', // 没有登陆跳回这个路由
              search: `?from=${rest.path}`, // 记录登陆之后需要跳回的路由路径
            }}
          />
      )
    }
  />
}

/**
 * 使用函数注入,和使用注解一样
 *
 * 因为使用mobx和react-router-dom 都是使用context去传入内容的
 * 会存在一个问题,因为mobx会去修改组件
 * observer(PrivateRoute) 执行时,会去修改组件的 shouldComponentUpdate
 * 此时会和react-router-dom产生一定的冲突:当路由发生变化时,组件不会重新渲染.这个在react-rouer的官方文档中有提到
 * 这个时候应该使用 withRouter 。当组件内容有更新时,强制更新组件.
 * 该方法需要注意:在配合 shouldComponentUpdate 被修改的组件是哟弄个时,必须放在最外面
 * @type {(React.FunctionComponent<P> & IWrappedComponent<IReactComponent>) | (React.ComponentClass<P> & IWrappedComponent<IReactComponent>) | (React.ClassicComponentClass<P> & IWrappedComponent<IReactComponent>)}
 */
const InjectedPriveRoute = withRouter(inject(((stores) => {
  return {
    login: stores.appState.user.login,
  }
}))(observer(PrivateRoute)))

PrivateRoute.prototype = {
  isLogin: PropTypes.bool,
  component:PropTypes.element.isRequired,//专门来形容组件的
}

/**
 * 如果没有传入isLogin 默认为false
 * @type {{isLogin: *}}
 */
PrivateRoute.defaultProps = {
  isLogin: false,
}
// {/*<Route path="/listItems" component={ListItems} key="ListItems" />,*/}
/**
 * @returns {*[]}
 */
export default () => [
  <Route path="/" render={() => <Redirect to="/homew" />} exact key="home" />,
  <Route path="/list" component={TopicList} exact key="list" />,
  <Route path="/detail" component={TopicDetail} key="detail" />,
  <Route path="/testApi" component={TestApi} key="testApi" />,
  <Route path="/homew" component={Homew} key="homew" />,
  <InjectedPriveRoute path="/listItems" component={ListItems} key="ListItems"/>,
  <Route path="/user/login" component={WrappedUserLogin} key="UserLogin" />,
]

user-login.jsx 文件

/* eslint-disable react/forbid-prop-types */
import React from 'react';
import { inject, observer } from 'mobx-react';
import { Redirect } from 'react-router-dom';
import querystring from 'query-string';
import { Layout, Breadcrumb, Form, Input, Icon, Checkbox, Button } from 'antd';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom'
import { createHashHistory } from 'history'

import './user-login.css';

const {
  Sider, Content,
} = Layout;

const { Item: FormItem } = Form;
const history = createHashHistory();

@inject((stores) => {
  return {
    userStore: stores.userStore,
  }
})
@observer
class UserLogin extends React.Component {
  constructor(props) {
    super(props);
    this.handleLogin = this.handleLogin.bind(this);
    this.getFrom = this.getFrom.bind(this);
  }

  /**
   * 获取回跳路径
   * @param location
   * @returns {*}
   */
  getFrom(location) {
    location = location || this.props.location;
    const query = querystring.parse(location.search);
    // 如果没有传入则进入登陆页面或有时直接进入登陆页面
    return query.from || '/user/info';
  }

  handleLogin(e, { userName, pwd }) {
    e.preventDefault();
    // 必须调用这个方法,不然不会显示错误信息
    this.props.form.validateFields((err, values) => {//eslint-disable-line
      if (!err) {
        this.props.userStore.login({ userName, pwd })
          .then((result) => {
            if (result) {
              history.push('/homew');
            }
          }, (error) => {
            console.log(error) //eslint-disable-line
          })
      }
    });
  }


  /**
   * 编写Store对象并准入
   * 路由跳转
   * 静态页面开发
   * 思考改为受控组件或注入到Store中
   * 开发登陆接口并绑定
   * @returns {*}
   */
  render() {
    const { getFieldDecorator, getFieldsValue } = this.props.form;
    const from = this.getFrom();
    const isLogin = this.props.userStore.wifLogin;
    // 如果已经登陆,则直接跳转到回跳路径
    if (isLogin) {
      return <Redirect to={from} />
    }
    return (
      <div>
        <Layout>
          <Content>
            <Breadcrumb>
              <Breadcrumb.Item>
                <Link to="/homew">
                主页
                </Link>
              </Breadcrumb.Item>
              <Breadcrumb.Item>
               登陆
              </Breadcrumb.Item>
            </Breadcrumb>
            {/* getFieldsValue获取所有注入组件的值,利用解构复制入参 */}
            <Form onSubmit={e => this.handleLogin(e, getFieldsValue())}>
              <FormItem>
                {getFieldDecorator('userName', {
                  rules: [{ required: true, message: 'Please input your username!' }],
                })(
                  <Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="Username" />,
                )}
              </FormItem>
              <FormItem>
                {getFieldDecorator('pwd', {
                  rules: [{ required: true, message: 'Please input your Password!' }],
                })(
                  <Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="Password" />,
                )}
              </FormItem>
              <FormItem>
                {getFieldDecorator('remember', {
                  valuePropName: 'checked',
                  initialValue: true,
                })(
                  <Checkbox>Remember me</Checkbox>,
                )}
                <a className="login-form-forgot" href="">Forgot password</a>
                <Button type="primary" htmlType="submit" className="login-form-button">
                  Log in
                </Button>
                Or <a href="">register now!</a>
              </FormItem>
            </Form>

          </Content>
          <Sider theme="light">
            <div id="sidebar">
              <div className="panel">
                <div className="header">
                  <span className="col_fade">关于</span>
                </div>
                <div className="inner">
                  <p>CNode:Node.js专业中文社区</p>

                  <p>在这里你可以:</p>
                  <ul>
                    <li>向别人提出你遇到的问题</li>
                    <li>帮助遇到问题的人</li>
                    <li>分享自己的知识</li>
                    <li>和其它人一起进步</li>
                  </ul>
                </div>
              </div>
            </div>
          </Sider>
        </Layout>
      </div>
    )
  }
}

UserLogin.wrappedComponent.propTypes = {
  userStore: PropTypes.object.isRequired,
};

UserLogin.propTypes = {
  form: PropTypes.object,
  location: PropTypes.object,
};

// 经过 Form.create 包装的组件将会自带 this.props.form 属性,this.props.form 提供的 API 如下:
// 注意:使用 getFieldsValue getFieldValue setFieldsValue 等时,应确保对应的 field 已经用 getFieldDecorator 注册过了。
const WrappedUserLogin = Form.create()(UserLogin);
export default WrappedUserLogin;

发布了30 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/wsl9420/article/details/86516874