十:以理论结合实践方式梳理前端 React 框架 ———集成框架

dva 框架简介

dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架

D.Va拥有一部强大的机甲,它具有两台全自动的近距离聚变机炮、可以使机甲飞跃敌人或障碍物的推进器、 还有可以抵御来自正面的远程攻击的防御矩阵。

—— 来自 守望先锋

dva 框架特性

  • 易学易用,仅有 6 个 api,对 redux 用户尤其友好,配合 umi 使用后更是降低为 0 API
  • elm 概念,通过 reducers, effects 和 subscriptions 组织 model
  • 插件机制,比如 dva-loading 可以自动处理 loading 状态,不用一遍遍地写 showLoading 和 hideLoading
  • 支持 HMR,基于 babel-plugin-dva-hmr 实现 components、routes 和 models 的 HMR

在使用 dva 前,你需要本地安装 dva-cli 相应的脚手架,浏览器自动打开 http://localhost:8000/#/,效果如下图

$ npm install dva-cli -g
$ dva -v
$ dva new dva-demo
? Do you insist on using dva-cli? (y/N) y
$ cd dva-demo
$ npm start

在这里插入图片描述


dva 框架结构

|-- config					-- 全局配置文件
|-- mock					-- mock 本地模拟数据接口
|-- node_modules			-- 项目依赖
|-- public					-- 项目静态页面
	|-- index.html
|-- src
	|-- assets				-- 静态资源库:字体、图标
	|-- components			-- 全局组件库
	|-- models				-- 全局模型库
	|-- pages				-- 容器组件库
	|-- services			-- API 文档
	|-- utils				-- 工具类库
	|-- index.css			-- 项目静态界面样式
	|-- index.js			-- 项目静态界面脚本
	|-- router.js			-- 项目路由文件
|-- .editorconfig
|-- .eslintrc
|-- .gitignore
|-- .roadhogrc.mock.js
|-- .webpackrc
|-- package-lock.json
|-- package.json
|-- README.md

1)页面组件分析 page

页面组件采用文件夹模式,首字母大写,包含:index.css 样式和 index.js 脚本两个文件,index.css 赋予当前组件的样式属性,index.js 赋予当前组件渲染。

// #################### 引入前端框架资源 ####################
import React, { useEffect } from 'react';
import { connect } from 'dva';

// #################### 引入静态资源部分 ####################
import './index.css';

// #################### 定义界面布局排版 ####################

// #################### 定义登录界面组件 ####################
function ExamplePage (props) {

    return (
        <div className="view-example">
            
        </div>
    );
}

// #################### 暴露 Redux 高阶组件 ####################
export default connect(({ example }) => ({
    // 这里通过 Redux 返回组件的 state
}))(ExamplePage);

在暴露 Redux 高阶组件可以看出,引入了一个 example 映射的 Redux —— 映射模型对象

2)页面模型分析 model

页面模型需要设置初始状态 state,一般为界面相关控件数据元素字段,通过页面组件 dispatch 调用 effects 相应的接口,根据接口返回值去执行 reducer 达到状态 state 的刷新;有的界面不涉及到接口调用,直接通过 reducer 去刷新状态 state 的值,从而达到界面的数据渲染。

export default {
	namespace: 'example',				// model 的名字,用来在页面中找到要调用哪一个model,就想id一样
	state: {},							// 用来存放数据的地方
	// 用来绑定监听页面事件,只有触发监听事件才执行,例:监听路由变化而处理某种业务
	subscriptions: {
		setup({ dispatch, history }) { 
		},
	},
	// 用来启用异步接口调用,得到结果后,put 传入到 reducer 更新 state
	effects: {
		*fetch({ payload }, { call, put }) {  // eslint-disable-line
			yield put({ type: 'save' });
		},
	},
	// 用来更新 state 状态,从而达到服务器渲染界面 SSR
	reducers: {
		save(state, action) {
			return { ...state, ...action.payload };
		},
	},

};

页面模型使用需要在 项目 src/index.js 内,引入模型,并进行模型绑定,如下

import dva from 'dva';
import { createBrowserHistory as createHistory } from 'history';				// 转成浏览器模式,路由不带 #
import ModelExample from './models/example';
// import Router from './router';
import './index.css';

// 1. Initialize
const app = dva({ history: createHistory() });

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

// 3. Model
app.model({ namespace: 'example', ...ModelExample });

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

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

3)接口服务分析 service

import request from '../utils/request';
// 暴露界面组件所需要的接口调用:
export async function query() {
	return await request('/api/users');
}

4)模板组件分析 components

组件传值通过 props 的方式进行父传子的单向传递,propTypes 用于校验 props 属性值

import React from 'react';

const Example = (props) => {
  return (
    <div>
      Example
    </div>
  );
};

Example.propTypes = {
};

export default Example;

5)路由管理分析 router.js

路由相对配置都已完成,主要涉及到子路由的配置,按上述说明添加子 Page,然后在 router.js 头部引入子 Page,最后在 Switch 组件内添加即可

import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import IndexPage from './pages/Index';
import LoginPage from './pages/Login';
import NoFoundPage from './pages/NoFound';
import WelcomePage from './pages/Welcome';

function RouterConfig({ history }) {
	return (
		<Router history={history}>
			<Switch>
				<Route exact path="/login" component={LoginPage} />
				<IndexPage exact>
					<Switch>
						<Route exact path="/" component={WelcomePage} />
						<Route exact path="/welcome" component={WelcomePage} />
						<Route exact path="*" component={NoFoundPage} />
					</Switch>
				</IndexPage>
			</Switch>
		</Router>
	);
}

export default RouterConfig;

6)静态资源引入方式

import './index.css';
import Lazy from '../../assets/img/lazy_load.jpg';      // 引入本地懒加载图片资源,方便处理图片裂图

7)页面生命周期函数

这里说明下,我们的项目所有的组件都是采用 Hooks 方式生成的 Function 函数式组件,想比较类组件每次都要声明 state 状态,使用 Function 函数式组件更好的达到组件的复用性,并且搭配高阶组件(Higher-Order Components)和渲染属性(Render Props)更好的缩减组件属性的迭代传递。

有时候,页面一渲染我们就需要使用 componentDidMount() 生命周期函数来执行接口调用,但是在 Function 函数式组件是没法使用 componentDidMount() 生命周期函数的,而 Hooks 为我们提供了 useEffect() 方法,类似于 componentDidMount(),这里不细讲 Hooks,详细了解请自行网上查询 —–

import React, { useEffect } from 'react';

function ExamplePage (props) {
	// 监听 Hook 的生命周期 useEffect 函数,相当于类组件 componentDidMount(),页面加载完成后执行
	useEffect(() => { dispatch(); }, []);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值