20 - Dva 框架使用 2 - 页面组合与model集成

基本要求

  1. 在空白脚手架的基础上添加一个跳转页面,记为MainPage,用于实现点击计数功能
  2. 在MainPage中组合两个功能组件,分比记为MainToolComponent和MainContextComponet
  3. 在MainToolComponent中添加两个按钮,实现页面中“增加技术”和“减少计数”的事件监听
  4. 在MainContextComponet中展示当前计数结果信息

实现准备

涉及概念与技术

  1. 路由表:实现从入口界面跳转至指定功能界面
  2. 容器组件:装载功能组件
  3. 功能组件:接收页面参数,展示model数据,发布操作更新请求
  4. models:记录技术结果,提供记录结果修改方法
  5. dva/connect: dva框架中对原生Redux封装后的connect函数
  6. dva/router: dva框架中对原始router的封装,封装后可通过dispatch实现路由跳转
  7. redux-actions插件:简化创建Redux的Action过程

主要操作步骤

  1. 定义MainModel,并注册到主程序中
  2. 定义MainPage组件,并配置到主路由中
  3. 定义MainToolComponent和MainContextComponet,并组合到MainPage组件
  4. 实现MainModel的reducer方法,实现MainModel中的state数据更新
  5. 绑定MainModel到MainToolComponent,并在MainToolComponent中向MainModel中发送更新计数指令
  6. 绑定MainModel到MainContextComponet,并在MainContextComponet中展示从MainModel中获取的数据

实现结果

MainModel定义与注册

MainModel定义

src\models\mainModel.js

export default {
    /**
     * 当前数据模型的命名空间
     * 1. 作为dispatch-action中的限定前缀
     * 2. 作为当前模型在redux中的属性名
     */
    namespace: 'mainModel',
  
    //当前数据模型所管理的数据
    state: {
        count : 100, //变化值
        name : "cyoubo" //不变值
    },
  
    //当前数据模型对数据操作函数
    //namespace+函数名,可以构成dispatch-action中的type值
    reducers: {
      plus(state, action) {
        return { ...state, count: state.count + action.payload };
      },
      subtraction(state, action) {
        return { ...state, count: state.count - action.payload };
      },  
    },


};

MainModel注册

src\index.js

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

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

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

// 3. Model
// 此处一定要开启注册,以便dva将当前model注入到redux空间中
app.model(require('./models/mainModel').default);

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

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

MainPage组件定义与路由配置

MainPage组件定义

src\routes\MainPage\MainPage.jsx

import React, { Component, Fragment } from 'react'
import MainContext from '../../components/MainContext/MainContext'
import MainTool from '../../components/MainTool/MainTool'

/**
 * 容器组件
 * 1. 内部只负责组合功能组件
 * 2. 对外需要于路由表挂接
 */
export default class MainPage extends Component {
    render() {
        return (
            <Fragment>
                <h2>this is count demo</h2>
                <MainContext></MainContext>
                <MainTool></MainTool>
            </Fragment>
        )
    }
}

路由配置

src\router.js

import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import IndexPage from './routes/IndexPage';
import MainPage from './routes/MainPage/MainPage'

/**
 * 路由配置表构架函数
 */
function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={IndexPage} />
        <Route path="/countDemo" component = {MainPage}></Route>
      </Switch>
    </Router>
  );
}

export default RouterConfig;

定义功能组件并组合

MainTool

src\components\MainTool\MainTool.jsx

import { Button } from 'antd'
import { connect } from 'dva'
import React, { Fragment } from 'react'
import * as actions from "../../action/MainModelActions"

/**
 * 计数器案例-按钮栏功能组件
 * @param {*} param0 由dva/connect绑定后,props属性中包含注入分发器dispatch
 */

 function MainTool(props) {

    //监听事件
    function onBtnPlusClick() {
        /**
         * 1. 发布计数器更新消息
         * 2. action由redux-actions创建
         * 3. plusAction的参数表示action所携带的参数,默认记为playload
         * 4. 此句等效于dispatch({type: "mainModel/plus", payload : 1})
         */
        props.dispatch(actions.plusAction(1))
    }

    function onBtnSubtraction() {
        props.dispatch(actions.subtractionAction(1))
    }

    return (
        <Fragment>
            <Button.Group>
                <Button type = "primary" onClick = {onBtnPlusClick}>plus one</Button>
                <Button type = "primary" onClick = {onBtnSubtraction}>subtraction one</Button>
            </Button.Group>
        </Fragment>
    )
}

/**
 * 1. 通过dva/connect高阶函数进行绑定,使得当前组件于redux托管空间发生关联
 * 2. connect后,当前组件的props属性中自动包含dispatch方法,用于发布消息
 * 3. connect函数没有参数,表示当前组件只是消息发布者,不是数据使用者
 */
export default connect()(MainTool)

MainContext

src\components\MainContext\MainContext.jsx

import { connect } from 'dva'
import React from 'react'

/**
 * 计数器案例-按钮栏功能组件
 * @param {*} param0 由dva/connect绑定后,props属性中包含注入的数据值和分发器
 * 注意:此处在对传入的props时进行了解构,只取其中的data属性
 */
 function MainContext({data}) {    
    return (
        <h4>
            {`current count is ${data.count}`} <br></br>
            {`current name is ${data.name}`}
        </h4>
    )
}

/**
 * 提取函数:告知connect函数,如何从redux空间中获取当前组件需要的数据
 * @param {}} reduxState 整个redux托管的数据空间
 */
const maps = (reduxState) => {
    //从redux空间中取出mainModel的数据数据,包裹成{data: {实际值}}的对象,传入到当前组件的props中
    return { data : reduxState.mainModel}
}

/**
 * 1. 通过dva/connect高阶函数进行绑定,使得当前组件于redux托管空间发生关联
 * 2. connect后,当前组件的props属性中自动包含dispatch方法,用于发布消息
 * 3. connect函数有参数,表示当前组件即是消息发布者,也是数据使用者
 */
export default connect(maps)(MainContext)

入口程序监听跳转

src\routes\IndexPage.js (样式文件省略)

import React from 'react';
import { connect } from 'dva';
import styles from './IndexPage.css';
import { routerRedux } from 'dva/router'

function IndexPage({dispatch}) {

  //监听点击事件实现路由跳转
  function onUlliClickHandle(event){
    event.preventDefault();
    const routerKey = event.target.dataset["key"]
    //路由跳转通过还是通过dispatch发布消息实现
    //此时的action由dva/router库中的routerRedux函数生成
    dispatch(routerRedux.push(`/${routerKey}`))
  } 


  return (
    <div className={styles.normal}>
      <h1 className={styles.title}>Yay! Welcome to dva!</h1>
      <ul className = {styles.list} onClick = {onUlliClickHandle}>
        <li><a href = "#" data-key = "countDemo">Count Demo</a></li>
      </ul>
    </div>
  );
}

IndexPage.propTypes = {
};

//绑定后,当前组件的props参数自动包含dispatch函数
export default connect()(IndexPage);

应用总结

Model注册与使用

  1. 所有的model都应该在index.js中进行注册,否则不能将model的state属性托管到redux中
  2. Model中的reducer都是为了修改当前model的state参数而执行的

组件组合

Model与组件通讯

  1. dva/connect函数的本质是将当前组件与整个redux托管空间进行了绑定,而不是和某一个特定的Model进行绑定
  2. 功能组件发布消息时,至需要通过调用props中的distach方法即可,向redux发送action
  3. 功能组件展示数据时,需要单独配置映射对象,告诉当前组件如何从redux空间中取得需要的数据(而不是从特定的model中取得数据)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值