UmiJS使用dva的几种方式

dva 是 React 应用框架,将React-Router + Redux + Redux-saga三个 React 工具库包装在一起,简化了 API,让开发 React 应用更加方便和快捷。

dva = React-Router + Redux + Redux-saga

注意使用Umijs创建项目默认就是ts模式,如果不是ts的可以吧数据类型定义和接口约束删除了 ,吧index.ts改成index.js就可以了

 

在项目加载的时候 定义的dva文件就被默认加载到dva列表中,也就说项目初始化的时候dva就被触发了,

并且dva是全局和vuex大致类似 下面我们来开始dva文件类型的创建

1.创建文件src/models/index.ts(定义dva)

文件夹必须叫models 这是因为UmiJS的约定式的 model 组织方式,否者他不去校验这个文件里的内容是否是dva ,就不会吧dva加入dva model 列表中

import { Effect, ImmerReducer, Reducer, Subscription } from 'umi';

export interface IndexModelState {
    name: string;
}

export interface IndexModelType {
    namespace: 'dva';
    state: IndexModelState;
    effects: {
        query: Effect;
    };
    reducers: {
        save: Reducer<IndexModelState>;
        // 启用 immer 之后
        // save: ImmerReducer<IndexModelState>;
    };
    subscriptions: { setup: Subscription };
}

const IndexModel: IndexModelType = {
    // 命名空间 注意这个namespace对应的值必须是唯一的不能重复,因为可以定义多个dva所以这里必须是唯一的做区分
   namespace: 'dva', // 内部状态 state: { name: '', }, // 异步程序 effects: { *query({ payload }, { call, put }) { // 正常这里发起请求 response最终获得接口返回值 // const response = yield call(这里是返回Promise对象发起请求, 参数) yield put({ type: 'save', payload: { name: '马丁的车夫' } }) }, }, // 同步函数 更新数据 reducers: { save(state, action) {return { ...state, ...action.payload, }; }, // 启用 immer 之后 // save(state, action) { // state.name = action.payload; // }, }, // 订阅 一开始就会被执行 subscriptions: { setup({ dispatch, history }) { // 监听路由变化 根据页面地址 触发指定的函数(每次切换路由都会被触发) return history.listen(({ pathname }) => { if (pathname === '/func') { // 调用 effects 对象里的异步函数体 // dispatch({ // type: 'query', // }); } }); }, }, }; export default IndexModel;

 

1.函数组件使用

方式一:

import { connect } from "umi";
import { Button } from 'antd';

const Index = (props: any) => {
    console.log(props) // 在props中获取对应的dva中state数据和方法

    // 不想在subscriptions中去订阅 
    // 就在这里判断一下初始化的时候调用dva中的effects异步发起请求获取最新数据
    if (!props.name) {
        props.onDecrease()
    }
    const handleClick = () => {
        props.onDecrease()
    }
    return (
        <div >
            获取dva中state的默认数据:{props.name}<br/>
            <Button type="primary" onClick={handleClick}>修改</Button>
        </div>
    )
}

// 获取到最新的state状态并且返回到函数组件中的props中去
const mapState = (state: any) => {
    const { name } = state.dva
    return {
        name: name
    }
}

// dva 异步操作
const mapDispatchToProps = (dispatch: (arg0: { type: string; payload?: any }) => void) => ({
    onDecrease() {
        dispatch({
            // 因为dva可以定义多个 所以这里要采用命名的方式去区分(一般只定义一个只作为入口)
            type: 'dva/query', // type:'要调用dva中的namespace/要调用dva中的effects具体函数名组成的'
            payload: { a: 111 }// 传递参数
        });
    }
})

export default connect(mapState, mapDispatchToProps)(Index)

 

方式二:(推荐)

import { connect, useSelector } from "umi";
import { Button } from 'antd';

const Index = (props: any) => {

    // 只要调用的dva中的state数据更新了 这里就能触发获取到最新数据
    const { name } = useSelector(function (state: any) {
        return state.dva
    });
    const handleClick = () => {
        // 调用dva中的effects异步
        props.dispatch({
            type: 'dva/query',
            payload: { a: 111 } //传递参数
        }).then(()=>{
            console.log('异步函数执行完毕并且返回结果更新了state')
        })
    }
    return (
        <div >
            获取dva中state的默认数据:{name}<br />
            <Button type="primary" onClick={handleClick}>修改</Button>
        </div>
    )
}


export default connect(({ dva }: any) => ({ dva }))(Index)

 

2.类(class)组件使用

方式一:

import React, { Component } from "react";
import { Button } from 'antd';
import { connect } from "umi";

// 对组件的props属性对象里的值做约定
interface IpRops {
    [x: string]: any
}

class Hello extends React.Component<IpRops> {
    handleClick = () => {
        console.log(this.props, '触发le.com')
        this.props.dispatch({
            type: 'dva/query',
            payload: { a: 111 }
        }).then(() => {
            console.log('更新完毕')
        });
    }
    render() {
        return (
            <div>
                获取dva中state的默认数据:{this.props.name}<br />
                <Button type="primary" onClick={this.handleClick}>修改</Button>
            </div>
        )
    }
}

const mapStateUsers = (state: any) => {
    return {
        name: state.dva.name
    }
};

export default connect(mapStateUsers)(Hello);

 

方式二:(推荐)

import React, { Component } from "react";
import { Button } from 'antd';
import { connect } from "umi";

// 对组件的props属性对象里的值做约定
interface IpRops {
    [x: string]: any
}

// this.state做约定
interface StateMode {
    [x: string]: any
}

class Hello extends React.Component<IpRops, StateMode> {

    constructor(props: any) {
        super(props)
        this.state = {}

    }
    componentDidMount() {

    }

    handleClick = () => {
        console.log('点击发起请求')
        this.props.dispatch({
            type: 'dva/query',
            payload: { a: 111 }
        }).then(() => {
            console.log('更新完毕')
        });
    }
    render() {
        const { name } = this.props.dva
        return (
            <div>
                获取dva中state的默认数据:{name}<br />
                <Button type="primary" onClick={this.handleClick}>修改</Button>
            </div>
        )
    }
}

export default connect(({ dva }: any) => ({ dva }))(Hello)

 

 

优化建议:

定义一个dva就可以了,作为一个入口文件,吧业务中使用到的模块用文件的方式进行导入

一个模块定义一个文件,最终全部导入到入口文件中对应的地方

 

我是马丁的车夫,欢迎转发收藏!

 

posted on 2022-01-26 09:48  马丁的车夫  阅读(3158)  评论(0编辑  收藏  举报