dva
create-react-app dva-app
cd dva-app
cnpm i dva keymaster -S
文件结构
├── /mock/ # 数据mock的接口文件
├── /src/ # 项目源码目录
│ ├── /components/ # 项目组件
│ ├── /routes/ # 路由组件(页面维度)
│ ├── /models/ # 数据模型
│ ├── /services/ # 数据接口
│ ├── /utils/ # 工具函数
│ ├── route.js # 路由配置
│ ├── index.js # 入口文件
│ ├── index.less
│ └── index.html
├── package.json # 定义依赖的pkg文件
└── proxy.config.js # 数据mock配置文件
计数器
用法 说明
app = dva(opts) 创建应用,返回 dva 实例
app.use(hooks) 配置 hooks 或者注册插件
app.model(model) 注册 model
app.router(({ history, app }) => RouterConfig) 注册路由表
app.start(selector?) 启动应用。selector 可选
import { Dispatch } from 'redux';
import dva, { connect } from 'dva';
import keymaster from 'keymaster';
import { RouterAPI } from 'dva';
import { Router, Route } from 'dva/router';
interface Counter1State {
number: 0
}
interface Counter2State {
number: 0
}
interface CombinedState {
counter1: Counter1State;
counter2: Counter2State;
}
const app = dva();
const delay = (millseconds: number) => {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve();
}, millseconds);
});
}
app.model({
namespace: 'counter1',
state: { number: 0 },
reducers: {//接收老状态,返回新状态
add(state) { //dispatch({type:'add'});
return { number: state.number + 1 };
},
minus(state) {//dispatch({type:'minus'})
return { number: state.number - 1 };
}
},
// 延时操作 调用接口 等待
effects: {
*asyncAdd(action, { put, call }) { //redux-saga/effects {put,call}
yield call(delay, 1000);//把100传给delay并调用,yield会等待promise完成
yield put({ type: 'add' });
}
},
subscriptions: {
keyboard({ dispatch }) {
keymaster('space', () => {
dispatch({ type: 'add' });
});
},
changeTitle({ history }) {
setTimeout(function () {
history.listen(({ pathname }) => {
document.title = pathname;
});
}, 1000);
}
}
});
app.model({
namespace: 'counter2',
state: { number: 0 },
reducers: {//接收老状态,返回新状态
add(state) { //dispatch({type:'add'});
return { number: state.number + 1 };
},
minus(state) {//dispatch({type:'minus'})
return { number: state.number - 1 };
}
}
});
type Counter1Props = Counter1State & { dispatch: Dispatch };
const Counter1 = (props: Counter1Props) => {
return (
<div>
<p>{props.number}</p>
<button onClick={() => props.dispatch({ type: 'counter1/add' })}>add</button>
<button onClick={() => props.dispatch({ type: 'counter1/asyncAdd' })}>asyncAdd</button>
<button onClick={() => props.dispatch({ type: 'counter1/minus' })}>-</button>
</div>
)
}
type Counter2Props = Counter2State & { dispatch: Dispatch };
const Counter2 = (props: Counter2Props) => {
return (
<div>
<p>{props.number}</p>
<button onClick={() => props.dispatch({ type: 'counter2/add' })}>+</button>
<button onClick={() => props.dispatch({ type: 'counter2/minus' })}>-</button>
</div>
)
}
const mapStateToProps1 = (state: CombinedState): Counter1State => state.counter1;
const ConnectedCounter = connect(
mapStateToProps1
)(Counter1);
const mapStateToProps2 = (state: CombinedState): Counter2State => state.counter2;
const ConnectedCounter2 = connect(
mapStateToProps2
)(Counter2);
app.router(
(api?: RouterAPI) => {
let { history } = api!;
return (
(
<Router history={history}>
<>
<Route path="/counter1" component={ConnectedCounter} />
<Route path="/counter2" component={ConnectedCounter2} />
</>
</Router>
)
)
}
);
app.start('#root');
namespace model 的命名空间,同时也是他在全局 state 上的属性,只能用字符串
state 初始值
reducers 以 key/value 格式定义 reducer。用于处理同步操作,唯一可以修改 state 的地方。由 action 触发。
effects 以 key/value 格式定义 effect。用于处理异步操作和业务逻辑,不直接修改 state。由 action 触发,可以触发 action,可以和服务器交互,可以获取全局 state 的数据等等。
subscriptions 以 key/value 格式定义 subscription。subscription 是订阅,用于订阅一个数据源,然后根据需要 dispatch 相应的 action。在 app.start() 时被执行,数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。
roadhog
roadhog 是基于 webpack 的封装工具,目的是简化 webpack 的配置
提供 server、 build 和 test 三个命令,分别用于本地调试和构建
提供了特别易用的 mock 功能
命令行体验和 create-react-app 一致,配置略有不同,比如默认开启 css modules
还提供了 JSON 格式的配置方式。
安装
npm i roadhog -g
mkdir zhufeng_roadhog
cd zhufeng_roadhog
cnpm init -y
cnpm i react react-dom -S
三个命令
roadhog server
roadhog build
roadhog test
.roadhogrc
{
“entry”: “src/index.js”,
“disableCSSModules”: false,
“publicPath”: “/”,
“outputPath”: “./dist”,
“extraBabelPlugins”: [],
“extraPostCSSPlugins”: [],
“autoprefixer”: null,
“proxy”: null,
“externals”: null,
“library”: null,
“libraryTarget”: “var”,
“multipage”: false,
“define”: null,
“env”: null,
“theme”: null,
}
参数 含义
entry 指定 webpack 入口文件,支持 glob 格式
outputPath 配置输出路径,默认是 ./dist
disableCSSModules 禁用 CSS Modules
publicPath 配置生产环境的 publicPath,开发环境下永远为 /
extraBabelPlugins 配置额外的 babel plugin。babel plugin 只能添加,不允许覆盖和删除
extraPostCSSPlugins 配置额外的 postcss 插件
autoprefixer 配置 autoprefixer 参数
proxy 配置代理
externals 配置 webpack 的 externals 属性
library 配置 webpack 的 library 属性
libraryTarget 配置 webpack 的 libraryTarget 属性
multipage 配置是否多页应用。多页应用会自动提取公共部分为 common.js 和 common.css
define 配置 webpack 的 DefinePlugin 插件,define 的值会自动做 JSON.stringify 处理
env 针对特定的环境进行配置。server 的环境变量是 development,build 的环境变量是 production
theme 配置主题,实际上是配 less 的 modifyVars
.roadhogrc.mock.js
export default {
// Support type as Object and Array
‘GET /api/users’: { users: [1,2] },
// Method like GET or POST can be omitted
'GET /api/users/1': { id: 1 },
// Support for custom functions, the API is the same as express@4
'POST /api/users/create': (req, res) => { res.end('OK'); },
};
去实现一个roadhog
package.json
#!/usr/bin/env node
const spawn = require('cross-spawn');
const chalk = require('chalk');
const script = process.argv[2];
//node bin/roadhog.js -v
switch (script) {
case "-v":
case "--version":
console.log(require("../package.json").version);
break;
case "build":
case "server":
result = spawn.sync(
"node",
[require.resolve(`../lib/${script}`)],
{ stdio: "inherit" }
);
process.exit(result.status);
break;
default:
console.log(`Unknown script ${chalk.cyan(script)}.`);
break;
}
build.js
const webpack = require("webpack");
const chalk = require("chalk");
function doneHandler(err, stats) {
console.log(stats.toJson().assets);
}
function build() {
let config = require("./config/webpack.config.prod");
var compiler = webpack(config);
compiler.run(doneHandler);
}
build()
webpack.config.prod
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve('dist'),
filename: "[name].js"
}
};
来源:CSDN
作者:花家地
链接:https://blog.csdn.net/weixin_42201346/article/details/104886740