Umi

1.UmiJS

  • UmiJS是一个类Next.JS的react开发框架
  • 基于一个约定,即pages目录下的文件即路由,而文件则导出react组件
  • 然后打通从源码到产物每个阶段,并配以完善的插件体系

约定式pages/配置式_routes.json=> 路由配置=>入口/路由文件=> Webpack 调试/构建=>生成html=> 部署=> Server

2. 安装

  1. npm i -g umi
  2. npm install bootstrap@3

3. 新建项目目录

  1. |—— dist/
  2. |—— nock/
  3. |—— src/
  4. |—— layouts/index.js
  5. |—— pages/
  6. |—— .umi/ // dev临时目录,需要添加到.gitignore
  7. |—— .umi-production // build 临时目录 回自动删除
  8. |—— document.ejs // HTML模板
  9. |—— .umirc.js // 配置文件
  10. |—— .env // 环境变量
  11. |—— package.json

3.1 新建项目

  1. mkdir rock-umi
  2. cd rock-umi
  3. cnpm init -y
  4. 生成indexpages
  5. umi g page index 安装页面模块
  6. umi g page profile
  7. umi dev 启动
  8. umi build 打包
  9. umi run test

4. 全局layout

  1. import React, { Component } from "react";
  2. import { Link } from "umi"
  3. import "bootstrap/dist/css/bootstrap.min.css"
  4. export default class Layout extends Component {
  5. render() {
  6. return (
  7. <>
  8. <nav className="navbar navbar-default">
  9. <div className="container-fluid">
  10. <div className="navbar-header">
  11. <a className="navbar-brand" href="#">
  12. UMI
  13. </a>
  14. </div>
  15. <ul className="nav navbar-nav">
  16. <li className="nav-link"><Link to="/">首页</Link></li>
  17. <li className="nav-link"><Link to="/user">用户管理</Link></li>
  18. <li className="nav-link"><Link to="/profile">个人中心</Link></li>
  19. </ul>
  20. </div>
  21. </nav>
  22. <div className="container">
  23. <div className="row">
  24. <div className="col-md-12">
  25. {this.props.children}
  26. </div>
  27. </div>
  28. </div>
  29. </>
  30. );
  31. }
  32. }

5. 用户管理

  • umi里约定目录下有_layout.js时会生成嵌套路由,以_layout.js为该目录的layout pages/user/_layout.js
  1. import React, { Component } from "react";
  2. import { Link } from "umi"
  3. export default class Layout extends Component {
  4. render() {
  5. return (
  6. <div className="row">
  7. <div className="col-md-3">
  8. <ul className="nav nav-stack">
  9. <li>
  10. <Link to="/user/list">用户列表</Link>
  11. <Link to="/user/add">新增用户</Link>
  12. </li>
  13. </ul>
  14. </div>
  15. <div className="col-md-9">
  16. {this.props.children}
  17. </div>
  18. </div>
  19. );
  20. }
  21. }

User/list.js

  1. import React, { Component } from "react";
  2. import { Link } from "umi";
  3. export default class list extends Component {
  4. render() {
  5. return (
  6. <ul className="list-group">
  7. <li className="list-group-item">
  8. <Link to={{ pathname: "/user/detail/1", state: { id: 1, name: "张三" } }}>张三 </Link>
  9. </li>
  10. <li className="list-group-item">
  11. <Link to={{ pathname: "/user/detail/2", state: { id: 2, name: "李四" } }}>李四 </Link>
  12. </li>
  13. </ul>
  14. );
  15. }
  16. }

User/add.js

  1. import React, { Component } from 'react'
  2. export default class add extends Component {
  3. render() {
  4. return (
  5. <form action="">
  6. 用户名<input type="text" className="form-control"/>
  7. 密码<input type="text" className="form-control"/>
  8. <br/>
  9. <input type="submit" className="btn btn-primary"/>
  10. </form>
  11. )
  12. }
  13. }
  • 动态路由[id].js

User/detail/[id].js

  1. import React, { Component } from 'react'
  2. export default class add extends Component {
  3. render() {
  4. let user = this.props.location.state || {}
  5. return (
  6. <div className="panel panel-default">
  7. <div className="panel-body">
  8. ID:{user.id}
  9. 姓名:{user.name}
  10. </div>
  11. </div>
  12. )
  13. }
  14. }

6. 权限路由

地址

通过指定高阶组件 wrappers 达成效果。

profile.js

  1. import React from 'react';
  2. import styles from './profile.css';
  3. import { history } from 'umi';
  4. function Profile() {
  5. return (
  6. <div>
  7. <h1 className={styles.title}>Page profile</h1>
  8. <button onClick={()=>history.push('/')}>返回</button>
  9. </div>
  10. );
  11. }
  12. Profile.wrappers = ['./wrappers/auth']
  13. export default Profile

Wrappers/auth.js

  1. import { Redirect } from 'umi'
  2. function useAuth(){
  3. console.log('没有权限');
  4. return false
  5. }
  6. export default (props) => {
  7. const { isLogin } = useAuth();
  8. if (isLogin) {
  9. return <div>{ props.children }</div>;
  10. } else {
  11. return <Redirect to="/" />;
  12. }
  13. }
  • 运行时路由
    app.js
export function patchRoutes({ routes }) {
  console.log(routes,'ssss');
  routes[0].routes.unshift({
    path: '/foo',
    exact: true,
    component: ()=> <div>foo</div>
  });
}

7. umi dev

UMI的功能

  • 根据pages生成路由配置
  • 生成完整的React项目进行运行

8. umi配置化路由的原理

通过webpack运行项目,读取配置好的routes配置,通过继承react-router 动态渲染routes, 将对象的值结构到route中动态加载渲染。

9. umi 进阶 按需加载

.umirc.js

    // 按需加载
    dynamicImport: {
      loading: '@/Loading'
    },

Loading.js

import React from 'react';
import './index.css'
export default () => {
  return <div className="loading">加载中...haha </div>;
};

10.约定式Mock数据

mock/api.js

export default {
    // 支持值为 Object 和 Array
    'GET /api/users': [{id: 1, name: "张三"},{id: 2, name: "李四" }] ,
    // GET 可忽略
    '/api/users/1': {id: 1, name: "张三"},

    // 支持自定义函数,API 参考 express@4
    'POST /api/users/add': (req, res) => {
      // 添加跨域请求头
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.end('ok');
    },
  }

11. SSR 服务端渲染和预渲染

服务端渲染和预渲染的好处都是在服务端进行渲染html,优点是可以减少白屏时间,更好的进行SEO,不同点是服务端渲染是客户端每次访问时生成最新代码最新数据,预渲染是每次构建时生成最新的代码加载到html中去,对于实时性强的服务端渲染更好,对于官网类的倾向使用预渲染技术,中后台管理系统类的谨慎使用服务端渲染技术

通过 exportStatic 结合 ssr 开启预渲染

export default {
  ssr: {},
  exportStatic: {
+   extraRoutePaths: async () => {
+     // const result = await request('https://your-api/news/list');
+     return Promise.resolve(['/news/1', 'news/2']);
+   }
  }
}