umi学习笔记

775 阅读4分钟

黑鸡是从去年十一月份开始接触到阿里的umi的,同时也是第一次接触dva的数据流,不过当时看到models文件夹下的文件中一大堆yieldcallput等陌生的写法就让我望而却步,当时虽然学习了一些,但是使用的一直不熟练,现在黑鸡准备好好整理一下使用方法,以便以后自己忘记。这里只写使用方法,不说比较深层次的东西(深的黑鸡也不懂)。

umi中dva的使用

首先我们在使用react的时候在早些时候都会使用redux来作为全局状态管理,并且我们都知道redux的学习难度是相对vue中的vuex来说是高于后者的,并且个人感觉使用体验也不如vuex,而dva就是一个基于reduxredux-saga的一个数据流方案,使用起来体验要比redux好的多。

基本使用

而在umi中使用dva还是比较简单的首先建立一个umi项目

yarn create @umijs/umi-app

然后跑起来,umi给我们约定了很多东西,所以我们不需要做太多导包什么的操作,首先,在src下新建一个models文件夹在下面创建一个global.js文件

|- src
    ...
    |- models
        |- global.js
    |- pages
        |- index.jsx
        |- index.less

获得了如上格式的文件结构后开始在global.js中撸代码

const GlobalModel = {
    namespace: 'global', //命名空间
    state: {
        count: 1
    },   //state是数据仓库
    reducers: {
        setCount(_, { payload: count }){
            return {
                count
            }
        }
    }
}

export default GlobalModel

这样就写了一个最最简单的model文件,接下来来解释一下这段代码的含义。

  • namespace是命名空间,我们在组件或者其他model文件中使用其他model的方法都需要加上命名空间
  • reducers可以理解成vuex中的mutations,里面可以进行同步操作修改state仓库,但是要注意和vuex的区别,vuex中是只修改state中的一部分,而dva中,应该说redux中是直接返回一个新的仓库

定义好仓库和方法我们如何在组件中使用呢,这得使用umi中的connectapi

// index.jsx
import React from 'react'
import { connect } from 'umi'

const Index = (props) => {
    const { count, dispatch } = props
    
    const addCount = () => {
        dispatch({
            type: 'global/setCount',
            payload: count + 1
        })
    }
    
    return (
        <>
            <div>{ count }</div>
            <button>增加</button>
        </>
    )
}

// 这里解构出的global就是我们的global仓库
export default connect(({ global })=>{
    return {
        count: global.count
    }
})(Index)

具体的使用方法如上代码所示,可以通过dispatch分发action来操作models文件中定义的逻辑

connect

connect的作用是连接组件和仓库,使用connect连接过的组件可以使用任何仓库中的数据,这样跨组件交流特别的方便。

connect方法支持一个回调函数作为参数,被此回调返回的数据会被注册到组件的props中,我们只需将数据中props中解构出来即可使用(不喜欢解构也可以不解构,但是要多写一个props

示例:

import { connect } from 'umi'

const Page = (props) => {
    
    const { count } = props

    return (
        <div>
            { count }
        </div>
    )
}

export default connect((store)=>{
    //回调中返回的数据会被注册到props中
    return {
        count: store.global.count
    }
})(Page)

这就是基本使用

异步操作effect

上面的models代码中reducers中只能进行同步操作,如果我们要发送Ajax请求或者其他异步操作就得把代码写在effect中了,修改一下global.js

//  models/global.js
import { getData } from 'xxx' //封装的Ajax请求

const GlobalModel = {
    namespace: 'global', //命名空间
    state: {
        count: 1,
        list: []
    },   //state是数据仓库
    reducers: {
        setCount(state, { payload: count }){
            return {
                ...state,
                count
            }
        },
        setList(state, { payload: list }){
            return {
                ...state,
                list
            }
        }
    },
    effect: {
        *getList({ payload }, { call, put }){
            //Ajax请求
            const data = yield call(getData, payload) 
            if(data.code === 200){
                yield put({
                    type: 'setList',
                    payload: data.data //把接口返回的数据传入
                })
            }
        }
    }
}

export default GlobalModel

上面就是effect的用法,注意effect中必须是一个Generator函数(工厂函数),call中可以调用接口的请求函数,只需要把封装的请求函数写入call的第一个参数就行了,第二个参数会被当作Ajax请求的参数,put相当于dispatch可以调用models中的方法,注意callput使用前面都必须加上yield关键字

subscriptions

接下来说最后一个属性subscriptions,这个属性中有一个setup方法,该方法可以监听路由变化并在其中进行一些操作,比如登录判断

//  models/global.js
import { getData } from 'xxx' //封装的Ajax请求
import { isLogin } from 'xxx'

const GlobalModel = {
    namespace: 'global', //命名空间
    state: {
        count: 1,
        list: []
    },   //state是数据仓库
    reducers: {
        setCount(state, { payload: count }){
            return {
                ...state,
                count
            }
        },
        setList(state, { payload: list }){
            return {
                ...state,
                list
            }
        }
    },
    effect: {
        *getList({ payload }, { call, put }){
            //Ajax请求
            const data = yield call(getData, payload) 
            if(data.code === 200){
                yield put({
                    type: 'setList',
                    payload: data.data //把接口返回的数据传入
                })
            }
        }
    },
    subscriptions: {
        setup({ dispatch, history }){
            return history.listen(({ pathname }) => {
                if(pathname === '/'){
                    //如果页面是首页,执行某些逻辑
                }
                
                if(!isLogin){
                    //如果没有登录,重定向到登录
                    history.push('/login')
                }
            })
        }
    }
}

export default GlobalModel

以上就是umidva的基本使用,更深的黑鸡也没接触到,在这里记下以便以后查看,up!up!up!