快速开始

快速开始

Dva 脚手架提供了快速创建项目的命令:

$ dva new dva-quickstart

项目结构

import dva from "dva"; //引入依赖
import "./index.css";
// 1. Initialize
const app = dva(); //初始化 dva应用
// 2. Plugins
// app.use({});          //使用中间件
// 3. Model
// app.model(require('./models/example').default); // 加载model层 (后面详细解释model)
// 4. Router
app.router(require("./router").default); // 引入router
// 5. Start
app.start("#root"); // 挂载dva应用

router.js 中提供了对于路由的定义:

import React from "react";
import { Router, Route, Switch } from "dva/router"; // 引入 router,用的就是 react-router
import IndexPage from "./routes/IndexPage"; // 引入路由绑定的高阶组件

// 按照从上到下的顺序开始匹配url规则,匹配到了就是展示对应的组件view
function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={IndexPage} />
      </Switch>
    </Router>
  );
}
export default RouterConfig;

路由页面 routes/IndexPage.js 中定义了页面结构:

import React from "react";
import { connect } from "dva";
import styles from "./IndexPage.css";

function IndexPage() {
  return (
    <div className={styles.normal}>
      <h1 className={styles.title}>Yay! Welcome to dva!</h1>
      <div className={styles.welcome} />
      <ul className={styles.list}>
        <li>
          To get started, edit <code>src/index.js</code> and save to reload.
        </li>
        <li>
          <a href="https://github.com/dvajs/dva-docs/blob/master/v1/en-us/getting-started.md">
            Getting Started
          </a>
        </li>
      </ul>
    </div>
  );
}

IndexPage.propTypes = {};
// 这里 connect方法就是redux的connect,后面的IndexPage表示绑定的高阶组件
// 在connect的第一个括号中,是可以拿到所有的model对象,这样就可以把对应的model对象绑定到我们的高阶组件上
export default connect()(IndexPage);

数据模型

export default {
  namespace: "example", // 命名空间 作为 connect方法 中获取model对象state的 id
  state: {}, // 初始化state
  subscriptions: {
    // 订阅
    setup({ dispatch, history }) {
      // eslint-disable-line
    },
  },
  effects: {
    // 异步action的handler
    *fetch({ payload }, { call, put }) {
      // eslint-disable-line
      yield put({ type: "save" });
    },
  },
  reducers: {
    //react-redux的reducers 用来接收action并且处理数据更新
    save(state, action) {
      return { ...state, ...action.payload };
    },
  },
};

更为复杂的模型定义如下:

export default {
  namespace: "list", // 这个namespace 是model的唯一识别id,在connect中需要使用这个绑定
  state: {},
  subscriptions: {
    setup({ dispatch, history }) {
      // eslint-disable-line
      return history.listen(({ pathname }) => {
        if (pathname === "/") {
          dispatch({
            type: "fetch",
            payload: {},
          });
        }
      });
    },
  },
  effects: {
    *fetch({ payload }, { call, put }) {
      // eslint-disable-line
      // 这里假装 获取到了服务器的数据
      const fetchData = [0, 1, 2, 3];
      yield put({
        type: "save",
        list: fetchData,
      });
    },
  },
  reducers: {
    // 保存
    save(state, action) {
      return { ...state, list: action.list };
    },
    // 新增
    add(state, action) {
      const [..._arr] = { ...state }.list;
      _arr.push(_arr.length);
      return {
        ...state,
        list: _arr,
      };
    },
    // 删除
    del(state, action) {
      return {
        ...state,
        list: state.list.filter((item, index) => {
          return index !== action.id;
        }),
      };
    },
  },
};