Bootstrap

React--Umi和Dva

目录

一、Umi

1.官网

2.安装与运行

3.配置式路由的创建

4.路由导航

4.1编程式--js的方式

4.2声明式--标签

5.重定向 --redirect

6.404页面

7.多级路由

8.约定式路由的创建

创建页面两种方式

二、Dva

1.官网

2.安装与运行

3.路由

4.路由导航

4.1编程式--js

4.2声明式--标签组件

5.model

6.读取数据

7.修改数据

8.effects--异步触发

扩展-Generator

9、effect使用

subscriptions 设置一个监听


一、Umi

简介:Umi,中文可发音为乌米,是可扩展的企业级前端应用框架。

           Umi 以路由为基础的(就是解决了之前使用react-router-dom的时候使用路由的复杂度)

1.官网

(1)2.0版本:https://v2.umijs.org/

(2)3.0版本:https://v3.umijs.org/

2.安装与运行

1.全局安装 : npm install -g umi@2 或者 yarn global add umi@2

2.测试安装版本: umi -v

3.新建文件夹 把cmd的路径切换到这个文件夹下

4.开始创建项目 yarn create @umijs/umi-app 或者 npm create @umijs/umi-app

5.下载依赖:cd到你刚才创建项目的文件夹下 npm install  或者  yarn

6.运行 yarn start  或者  npm start

3.配置式路由的创建

1.在src下的pages文件夹下 新建你对应的路由页面

2.配置路由规则 在.umirc.ts文件中进行配置

import { defineConfig } from 'umi';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  routes: [
    { path: '/', component: '@/pages/index' },
    // 仿照默认的内容自行添加
    { path: '/home', component: '@/pages/home/home' },
    { path: '/phone', component: '@/pages/phone/phone' },
  ],
  fastRefresh: {},
});

4.路由导航

4.1编程式--js的方式

import React from 'react'
// 注意引用是来自于umi的
import {Link,history} from "umi"
export default function Topbar() {
    let fun=()=>{
        // 编程式导航
        history.push("/phone")
    }
  return (
    <div>
        <Link to="/">首页</Link>
        <Link to="/home">home</Link>
        <Link to="/phone">手机</Link>
        <hr />
        <button onClick={fun}>点我去手机</button>
    </div>
  )
}

4.2声明式--标签

借助Link 这个标签来完成,使用to属性来表明路径 。

import React from 'react'
// 注意引用是来自于umi的
import {Link} from "umi"
export default function Topbar() {
  return (
    <div>
        <Link to="/">首页</Link>
        <Link to="/home">home</Link>
        <Link to="/phone">手机</Link>

    </div>
  )
}

5.重定向 --redirect

umirc文件里面进行配置

import { defineConfig } from 'umi';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  routes: [
    { path: '/index', component: '@/pages/index' },
    // 仿照默认的内容自行添加
    { path: '/home', component: '@/pages/home/home' },
    { path: '/phone', component: '@/pages/phone/phone' },
    // 路由重定向    exact精准匹配
    { path: '/', redirect:"/index",exact:true },
  ],
  fastRefresh: {},
});

6.404页面

1.创建对应404页面

2.配置404规则

import { defineConfig } from 'umi';

export default defineConfig({
  nodeModulesTransform: {
    type: 'none',
  },
  routes: [
    { path: '/index', component: '@/pages/index' },
    // 仿照默认的内容自行添加
    { path: '/home', component: '@/pages/home/home' },
    { path: '/phone', component: '@/pages/phone/phone' },
    // 路由重定向    exact精准匹配
    { path: '/', redirect:"/index",exact:true },

    // 404页面
    { path: '*', component: '@/pages/no/no' },
  ],
  fastRefresh: {},
});

7.多级路由

1.创建多级路由页面

2.配置多级路由规则(在对应的以及路由规则中进行嵌套)

 { 
      path: '/home', 
      component: '@/pages/home/home',
      // 配置多级路由
      routes:[
        { path: '/home/era', component: '@/pages/er/era' },
        { path: '/home/erc', component: '@/pages/er/erc' },
      ]
    
    },

3.千万不要忘了 设置二级路由出口 (在对应的路由页面中配置)props.children 多级路由的出口

8.约定式路由的创建

umi在创建路由时,我们也可以不需要配置路由规则,从而达到路由效果,这种方式就叫约定式 。

创建页面两种方式

1.手工创建:同原来

2.命令创建:在项目的根路径下 输入 umi g page 你要创建的页面名 (就会在pages文件夹下 自动创建对应的页面)

二、Dva

简介:

dva 首先是一个基于 reduxredux-saga 的数据流方案,然后为了简化开发体验 (dva就是对react进行了语法上面的简化 让我们在react中使用状态管理工具变得更简单)

redux-saga 就是redux进行异步操作的一个技术

1.官网

地址:DvaJS

2.安装与运行

1.全局安装 npm install -g dva-cli

2.测试 dva -v

3.cd到指定文件夹之下 dva new 你的项目名

4.cd到项目下面 npm install之后再启动

5.启动 npm start

3.路由

在dva中使用他内置的路由我们可以把路由页面创建到src下的routes文件夹中 当然我们也可以重新创建一个文件夹来容纳路由页面

1.创建路由页面

2.配置路由规则 src文件夹下的router.js文件中来进行编写

import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import IndexPage from './routes/IndexPage';
// 1.引用路由页面
import Home from "./routes/home.jsx"
import Phone from "./routes/phone.jsx"
import User from "./routes/user.jsx"

function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={IndexPage} />
        {/* 2.配置路由规则 */}
        <Route path="/home" exact component={Home} />
        <Route path="/phone" exact component={Phone} />
        <Route path="/user" exact component={User} />
      </Switch>
    </Router>
  );
}

export default RouterConfig;

4.路由导航

4.1编程式--js

props.history.push("/去哪里")

注意:使用编程式导航必须在被路由所管理的页面中进行才可以,否则就要使用withRouter这个高阶组件来传递路由跳转的属性

import React from 'react'

// 引用Link组件来自于dva 的路由
import {Link,withRouter} from "dva/router"

function topbar(props) {
    let fun=()=>{
        // 编程式导航\
        // 在组件中定义了一个编程式导航
        // 但是在运行的时候发现push没有定义
        // 因为 在使用编程式导航的时候   由于当前组件不是被路由所管理的页面  那么他就不具备路由跳转的功能
        // 就会出现push没有定义

        // 所以我们就要使用HOC--高阶组件--withRouter来解决
        props.history.push("/user")
    }
  return (
    <div>
        
        {/* 声明式导航 */}
        <Link to="/">首页</Link>
        <Link to="/home">home</Link>
        <Link to="/phone">phone</Link>
        <Link to="/user">user</Link>

        {/* 编程式 */}
        <button onClick={fun}>点我去user</button>

    </div>
  )
}
export default withRouter(topbar)

4.2声明式--标签组件

import React from 'react'

// 引用Link组件来自于dva 的路由
import {Link} from "dva/router"

export default function topbar() {
  return (
    <div>
        {/* 声明式导航 */}
        <Link to="/">首页</Link>
        <Link to="/home">home</Link>
        <Link to="/phone">phone</Link>
        <Link to="/user">user</Link>
    </div>
  )
}

5.model

dva 通过 model 的概念把一个领域的模型管理起来,包含同步更新 state 的 reducers,处理异步逻辑的 effects,订阅数据源的 subscriptions 。

(dva中的model 就是用来把状态管理工具进行模块化设置的,为什么要设置模块化?

因为组件多了 数据与修改就变得很多,如果我们把一个项目的所有数据与修改都放在一起,后期维护就很麻烦,所以这个时候我们就可以进行模块拆分)

1.在src的modules文件夹中 创建对应的模块文件

2.编写内容

export default {
    namespace: 'userm',//命名空间---就是给当前这个模块起个名字(唯一的)
    state: {
        name:"我是user模块中的数据"
    },//存放数据的
    subscriptions: {//类似于一个监听  在里面可以绑定很多个监听的方案
    },
    effects: {//类似于vuex的actions  进行异步触发的
    },
    reducers: {//  修改上面的state的地方
    },
  };

3.把我们新建的模块和项目建立关联

在srtc下的index.js中建立

import dva from 'dva';
import './index.css';

// 1. Initialize
const app = dva();

// 2. Plugins
// app.use({});

// 3. Model  就是建立我们模块与项目的位置
// app.model(require('./models/example').default);
app.model(require('./models/homem').default);
app.model(require('./models/phonem').default);
app.model(require('./models/userm').default);

// 4. Router
app.router(require('./router').default);

// 5. Start
app.start('#root');

6.读取数据

import React from 'react'
import Topbar from "../components/topbar.jsx"
// 1.引用组件和模块的链接工具--connect  是一个方法  当这个方法被调用的时候他才是一个链接的高阶组件
import { connect } from 'dva'

function Home(props) {
  return (
    <div>
        <Topbar></Topbar>
        {/* props.state.你要引用的模块的命名空间名字.数据名 */}
        <h1>我想读取dva中模块的数据----{props.state.homem.name}</h1>
        <h1>我想读取dva中另一个模块的数据----{props.state.userm.name}</h1>
    </div>
  )
}
// 2.设置数据
export default connect(state=>({state}))(Home)

7.修改数据

1.在组件内通过dispatch来触发修改

import React from 'react'
import Topbar from "../components/topbar.jsx"
import { connect } from 'dva'
 function Phone(props) {
    let fun=()=>{
        // 触发dva的数据修改
        // dispatch({type:模块的命名空间名字/你的reducer的名字})
        props.dispatch({type:"phonem/UP_NAME"})
    }
  return (
    <div>
        <Topbar></Topbar>
        phone----{props.state.phonem.name}
        <button onClick={fun}>点我修改数据</button>
    </div>
  )
}
export default connect(state=>({state}))(Phone)

2.编写对应修改的reducers

export default {

    namespace: 'phonem',//命名空间---就是给当前这个模块起个名字(唯一的)
  
    state: {
        name:"我是phone模块中的数据"
    },//存放数据的
  
    subscriptions: {//类似于一个监听  在里面可以绑定很多个监听的方案
    
    },
  
    effects: {//类似于vuex的actions  进行异步触发的
    
    },
  
    reducers: {//  修改上面的state的地方
        // state:就是上面的数据源
        // payload就是接收dispatch的第二个参数
        UP_NAME(state,payload){
            return {...state,name:"我吧phone的数据修改了"}
        }
    },
  
  };

8.effects--异步触发

扩展-Generator

在dva中如果我们要使用effects来进行异步触发 那么我们需要使用es6中新特性之--- Generator

Generator 函数的作用:让我们的函数可以根据我们开发者的需求走走停停

1.如果我们想控制函数的执行或者暂停 那么我们需要把函数变成generator函数 就是在function关键字 与函数名之间加一个*号

    function *fun(){
            console.log(111);
            console.log(222);
            console.log(333);
        }

2.我们需要让函数根据我们的需要走走停停 那么我们就必须在函数中加入表示 来表明暂停的位置是哪里 yield(就是函数暂停的分割线)

   function *fun(){
            console.log(111);
            yield
            console.log(222);
            yield
            console.log(333);
        }

3.我们在调用的时候 还需要告诉当前的generator函数 你要执行 next()

 function *fun(){
            console.log(111);
            yield
            console.log(222);
            yield
            console.log(333);
        }
        // 我们要执行函数中的内容
        let funger=fun()
        // 想让函数执行
        funger.next()
        funger.next()

9、effect使用

1.在组件中还是使用dispatch来触发

import Topbar from "../components/topbar.jsx"
import {connect} from "dva"
 function User(props) {
    let fun=()=>{
        // 触发effects进行异步操作
        // props.dispatch({type:"你要调用的模块命名空间名字/effect的名字"})
        props.dispatch({type:"userm/LINK"})
    }
  return (
    <div>
        <Topbar></Topbar>
        user
        
       <button onClick={fun}>点我触发异步操作</button> 
    </div>
  )
}
export default connect()(User)

2.编写effects异步触发器


export default {
    namespace: 'userm',//命名空间---就是给当前这个模块起个名字(唯一的)
    state: {
        name:"我是user模块中的数据"
    },//存放数据的
    subscriptions: {//类似于一个监听  在里面可以绑定很多个监听的方案
    
    },
    effects: {//类似于vuex的actions  进行异步触发的  effects的函数必须是一个Generator函数
        *LINK(){
            console.log("我被触发了");
        }
    },
    reducers: {//  修改上面的state的地方
     
    },
  };

3.设置请求

在dva中默认已经帮助我们封装好了异步请求 我们不需要单独去配置与下载 在service文件夹下新建文件 创建请求

import request from '../utils/request';

export function query() {
  return request('http://localhost:8888/userlist/getlink');
}

4.把写好的请求在effects中使用

// 1.引用我们刚才写好的请求
import {query} from "../services/userlink.js"
export default {
    namespace: 'userm',
    state: {
        name:"我是user模块中的数据"
    },
    subscriptions: {
    
    },
    effects: {
        // 2.使用异步请求
        // call 调用异步操作 并且得到成功的值
        *LINK({payload},{put,call}){
            console.log("我被触发了");
            // 下一步 使用call来获取成功的返回值
          let data= yield call(query
        }
    },
    reducers: {
     
    },
  };
  

5.把请求成功的数据复制给state方便组件使用( 先要交给reducers )

// 1.引用我们刚才写好的请求
import {query} from "../services/userlink.js"
export default {
    namespace: 'userm',
    state: {
        name:"我是user模块中的数据"
    },
    subscriptions: {
    
    },
    effects: {
        // 2.使用异步请求
        // call 调用异步操作 并且得到成功的值
        // put把effects中触发reducers
        *LINK({payload},{put,call}){
            console.log("我被触发了");
            // 下一步 使用call来获取成功的返回值
          let data= yield call(query

        //   把请求来的数据通过reducers修改给state
        // 下一步  通过put触发reducers
            yield put({type:"UP_NAME",data})

        }
    },
    reducers: {
     
    },
  };

6编写对应的reduicers

// 1.引用我们刚才写好的请求
import {query} from "../services/userlink.js"
export default {
    namespace: 'userm',
    state: {
        name:"我是user模块中的数据"
    },
    subscriptions: {
    },
    effects: {
        // 2.使用异步请求
        // call 调用异步操作 并且得到成功的值
        // put把effects中触发reducers
        *LINK({payload},{put,call}){
            console.log("我被触发了");
            // 下一步 使用call来获取成功的返回值
          let data= yield call(query

        //   把请求来的数据通过reducers修改给state
        // 下一步  通过put触发reducers
            yield put({type:"UP_NAME",data})

        }
    },
    reducers: {
        // 设置修改
        UP_NAME(state,payload){
            return {...state,name:payload.data}
        }
    },
  };

7 在页面读取数据

import Topbar from "../components/topbar.jsx"
import {connect} from "dva"
 function User(props) {
    let fun=()=>{
        // 触发effects进行异步操作
        // props.dispatch({type:"你要调用的模块命名空间名字/effect的名字"})
        props.dispatch({type:"userm/LINK"})    
    }
  return (
    <div>
        <Topbar></Topbar>
        user---{props.state.userm.name}
        
       <button onClick={fun}>点我触发异步操作</button> 
    </div>
  )
}
export default connect(state=>({state}))(User)

8 在运行之后出现了跨域问题 添加跨域 项目的根路径下有一个webpackrc的文件中添加跨域

{
    "proxy":{
        "/api":{
             "target":"http://localhost:8888",
             "changeOrigin":true,
             "pathRewrite":{
               "^/api":"/"
             }
        }
    }
}

9.修改请求地址为/api

import request from '../utils/request';

export function query() {
  return request('/api/userlist/getlink');
}

10.修改下请求的传递数据

// 1.引用我们刚才写好的请求
import {query} from "../services/userlink.js"
export default {
    namespace: 'userm',
    state: {
        name:"我是user模块中的数据"
    },
    subscriptions: {
    
    },
    effects: {
        // 2.使用异步请求
        // call 调用异步操作 并且得到成功的值
        // put把effects中触发reducers
        *LINK({payload},{put,call}){
            console.log("我被触发了");
            // 下一步 使用call来获取成功的返回值
          let data= yield call(query)
          console.log(data.data.msg);

        //   把请求来的数据通过reducers修改给state
        // 下一步  通过put触发reducers
            yield put({type:"UP_NAME",data:data.data.msg})

        }
    },
    reducers: {
        // 设置修改
        UP_NAME(state,payload){
            return {...state,name:payload.data}
        }
    },
  };
  

subscriptions 设置一个监听

可以在里面设置一些监听函数 必须页面修改了 鼠标移动了等等等

;