Dva - 起步

https://github.com/76351506/dva-cli.git

Dva 基础

namespace

model 的命名空间,同时也是他在全局 state 上的属性,只能用字符串,不支持通过 . 的方式创建多层命名空间。

state

初始值,优先级低于传给 dva() 的 opts.initialState。

reducers

以 key/value 格式定义 reducer。用于处理同步操作,唯一可以修改 state 的地方。由 action 触发。
格式为 (state, action) => newState 或 [(state, action) => newState, enhancer]。
详见: https://github.com/dvajs/dva/blob/master/packages/dva-core/test/reducers.test.js

effects

以 key/value 格式定义 effect。用于处理异步操作和业务逻辑,不直接修改 state。由 action 触发,可以触发 action,可以和服务器交互,可以获取全局 state 的数据等等。
格式为 (action, effects) => void 或 [(action, effects) => void, { type }]。

subscriptions

以 key/value 格式定义 subscription。subscription 是订阅,用于订阅一个数据源,然后根据需要 dispatch 相应的 action。在 app.start() 时被执行,数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。
格式为 ({ dispatch, history }, done) => unlistenFunction。

不会配置装饰器可参考

https://www.yuque.com/docs/share/c4c1479e-114c-4b17-ab70-65748a3db54b?# 《在 dva 使用装饰器》

开始

  • 引入 history 模块
  • 配置
  • index.js
1
2
3
4
5
6
7
8
9
10
11
import dva from "dva";
//引入history
import { createBrowserHistory } from "history";
//引入路由配置
import router from "router";
//实例化dva
const app = dva({ history: createBrowserHistory() });
//挂载路由
app.router(router);
//挂载节点
app.start("#root");

router 路由设置

  • index.js
1
2
3
4
5
6
7
8
9
import React from "react";
import RouterMap from "./map";
import Routes from "./routes";

function RouterView(props) {
const routes = props.routes ? props.routes : Routes;
return <RouterMap routes={routes} {...props} />;
}
export default RouterView;

routes.js —路由表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Index from "../containers/Index";
import Login from "../containers/Login";

export default [
{
path: "/index",
name: "index",
component: Index,
token: true,
},
{
path: "/login",
name: "login",
component: Login,
},
];

map.js–渲染路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import React, { Component } from "react";
//引入dva/router的路由组件
import { Router, Route, Switch, Redirect } from "dva/router";

class RouterMap extends Component {
render() {
const { routes, history } = this.props;
const defaultRoute = (
<Redirect from="/" to="/index/home" key={"default"} exact></Redirect>
);
return (
<Router history={history}>
<Switch>
{routes
.map((item) => {
//有children就等于否则等于【】
const children = item.children === undefined ? [] : item.children;
const Comp = item.component;
//判断是否需要token鉴权
if (item.token) {
if (!localStorage.getItem("token")) {
return (
<Redirect
key={item.name + "red"}
to="/login"
from={item.path}
/>
);
}
}

return (
<Route
key={item.name + "route"}
path={item.path}
component={() => {
return <Comp routes={children} history={history}></Comp>;
}}
/>
);
})
.concat([defaultRoute])}
</Switch>
</Router>
);
}
}
export default RouterMap;

dva 路由传参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//state传参
this.props.history.push("/index/productDetail", {
pid: text.pid,
});
//接收参数
this.props.location.state.pid;

由于组件没有location我们需要使用装饰器来给组件添加方法;
import { withRouter } from "dva/router";

@withRouter
class productDetail extends Component {
render() {
return <></>;
}
}

封装

  • 目录结构
1
2
3
4
5
store-
|-index.js //加载model
|-model文件夹
-| user.js//用户仓库
-| home.js//首页仓库

index.js -加载所有仓库

1
2
3
4
5
6
7
8
9
10
const context = require.context("./model", false, /\.js$/);
//通过context.keys()获取model目录下面的文件名

//遍历文件名,获取文件内容,返回个数组
const getModel = context.keys().map((key) => context(key));

export const createModel = function (app) {
//遍历获取到的model数组集合,分别将每一个model绑定到 app.model()
return getModel.map((model) => app.model(model.default));
};
  • model 文件夹-存放仓库
  • user.js-用户仓库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import { _getUserByToken } from "@/api/user";
//axios请求数据

export default {
//命名空间
namespace: "user",
//初始值
state: { token: "", uid: "" },
//唯一可以修改state的地方
reducers: {
TOKEN(state, { payload }) {
// 保存数据到 state
return { ...state, token: payload };
},
UID(stata, { payload }) {
return { ...state, uid: payload };
},
},
//处理异步的state数据
effects: {
*getuser({ token }, { put, call }) {
let res = yield call(_getUserByToken, token);
//判断code为1改变uid
if (res.code) {
yield put({ type: "UID", payload: res.uid });
}
},
},
};