umi官网
Umi,中文可发音为乌米,是可扩展的企业级前端应用框架。Umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求。
Umi 是蚂蚁金服的底层前端框架,已直接或间接地服务了 3000+ 应用,包括 java、node、H5 无线、离线(Hybrid)应用、纯前端 assets 应用、CMS 应用等。他已经很好地服务了我们的内部用户,同时希望他也能服务好外部用户。
首先得有 node,并确保 node 版本是 10.13 或以上。(mac 下推荐使用 nvm 来管理 node 版本)
$ node -v
v10.13.0
# 国内源
$ npm i yarn tyarn -g
# 后面文档里的 yarn 换成 tyarn
$ tyarn -v
# 阿里内网源
$ tnpm i yarn @ali/yarn -g
# 后面文档里的 yarn 换成 ayarn
$ ayarn -v
脚手架
先找个地方建个空目录。
$ mkdir myapp && cd myapp
通过官方工具创建项目,
$ yarn create @umijs/umi-app
# 或 npx @umijs/create-umi-app
$ yarn
$ yarn start
除配置式路由外,Umi 也支持约定式路由。约定式路由也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置。
如果没有 routes 配置,Umi 会进入约定式路由模式,然后分析 src/pages 目录拿到路由配置。
import {
defineConfig } from 'umi';
export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
// routes: [
// { path: '/', component: '@/pages/index' },
// ],
fastRefresh: {
},
});
直接编写dva代码,umi会自动引用dva,无需配置
dva官网
dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。
接着新建文件count.js
export default {
namespace: 'count', 命名空间名字,必填
//state就是用来放初始值
state: {
number: 99,
},
// 能改变界面的action应该放这里,这里按官方意思不应该做数据处理,只是用来return state 从而改变界面
reducers: {
add(state, {
payload }) {
console.log('新增触发', payload);
return {
...state, number: state.number + payload };
},
},
// 与后台交互,处理数据逻辑的地方
effects: {
},
};
};
import {
connect } from 'dva';
const Index = (props) => {
console.log('props', props);
const {
number, add } = props;
const handleAdd = () => {
console.log('新增');
add(1);
};
return (
<div>
counter:{
number}
<button onClick={
handleAdd}>+1</button>
<button>-1</button>
</div>
);
};
const mapStateProps = (state) => {
return {
number: state.count.number,
};
};
const actionCreater = {
add: (payload) => {
return {
type: 'count/add',
payload,
};
},
};
export default connect(mapStateProps, actionCreater)(Index);
props.dispatch({
type: 'count/add',
payload: 5,
});
import {
connect } from 'dva';
const Index = (props) => {
console.log('props', props);
const {
number } = props;
const handleAdd = () => {
console.log('新增', props.dispatch);
props.dispatch({
type: 'count/add',
payload: 5,
});
};
return (
<div>
counter:{
number}
<button onClick={
handleAdd}>+1</button>
<button>-1</button>
</div>
);
};
const mapStateProps = (state) => {
return {
number: state.count.number,
};
};
const actionCreater = {
add: (payload) => {
return {
type: 'count/add',
payload,
};
},
};
export default connect(mapStateProps)(Index);
const namespace = 'count';
const selectState = (state) => state[namespace];
export default {
namespace: 'count', 命名空间名字,必填
//state就是用来放初始值
state: {
number: 99,
id: 999,
},
// 能改变界面的action应该放这里,这里按官方意思不应该做数据处理,只是用来return state 从而改变界面
reducers: {
add(state, {
payload }) {
console.log('新增触发', payload);
return {
...state, number: state.number + payload };
},
overrideStateProps(state, {
payload }) {
return {
...state,
...payload,
};
},
updateStateProps(state, {
payload }) {
const {
name, value } = payload;
return {
...state,
...{
[name]: {
...state[name], ...value } },
};
},
},
// 与后台交互,处理数据逻辑的地方
effects: {
//生成器函数
/**
*
* @param {*} action
* @param {*} call //获取异步数据
* @param {*} put //同步触发reducers中的函数
* @param {*} select //获取state数据
*/
*addAsync(action, {
call, put, select }) {
console.log('action');
const {
id } = yield select(selectState);
// console.log('id', id);
// let res = yield call();
// console.log('res', res);
// yield put({ type: 'add', res });
},
},
subscriptions: {
// 订阅监听,比如我们监听路由,进入页面就如何,可以在这写
setup({
dispatch, history, query }) {
return history.listen(async ({
pathname, search, query }) => {
if (pathname === '/testdemo') {
// 当进入testdemo这路由,就会触发fetchUser方法
dispatch({
type: 'fetchUser' });
}
});
},
},
};