dva搭建项目实例

文章目录

  • 安装dva-cli
  • 创建应用
  • 项目结构说明
  • 使用antd
  • 添加列表页面
  • 定义model
  • 使用connect绑定models
  • 获取数据
  • 添加新数据

安装dva-cli

$ npm install dva-cli -g

创建应用

$ dva new dva-demo
$ cd dva-demo
$ npm start

dva搭建项目实例_第1张图片

项目结构说明

dva搭建项目实例_第2张图片

  1. assets:媒体文件,存放图片等。

  2. components:最基础的组件。存放基本的UI组件,这些组件接收外部传过来的参数(数据),并将这些数据渲染到界面。根据传入参数的不同,界面渲染也不同。

  3. models:model是dva中的一个重要概念,可以看作数据层。

    应用的state被存储在一个object tree中,应用的初始state在model中定义,也就是说,由model state组成全局state。

    dva将model以namespace作为唯一标识进行区分,然后将所有model的数据存储到redux中的store里面。在引用的时候,通过各个model的namespace进行引用。

    Model是一个处理数据的地方,在model里面调用service层获取数据。

  4. routes:将component组件和store里面的数据进行包装,生成一个新的有数据的组件,然后在router.js配置文件中引用routes中的组件。

  5. services:负责向后台请求数据,在services里调用后台提供的api获取数据。

  6. utils:工具类,比如常见的后台接口请求工具类。

  7. router.js:配置整个应用的路由

  8. index.js:中仍然应用的入口文件。

使用antd

通过 npm 安装 antd 和 babel-plugin-import 。
babel-plugin-import 是用来按需加载 antd 的脚本和样式的。

$ npm install antd babel-plugin-import --save

编辑 .roadhogrc,使 babel-plugin-import 插件生效。

{

"extraBabelPlugins": [

["import", {"libraryName": "antd", "libraryDirectory": "es", "style": "css"}]

}

添加列表页面

用 dva-cli 生成路由:

$ dva g route list

dva搭建项目实例_第3张图片

routes里自动生成文件

打开router.js,将新生成的route移动到switch里。
dva搭建项目实例_第4张图片
编辑List.js

import React from 'react';
import { connect } from 'dva';
import styles from './List.css';
import { Table, Divider, Tag } from 'antd';
const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
    render: text => <a>{text}</a>,
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address',
  },
  {
    title: 'Tags',
    key: 'tags',
    dataIndex: 'tags',
    render: tags => (
      <span>
        {tags.map(tag => {
          let color = tag.length > 5 ? 'geekblue' : 'green';
          if (tag === 'loser') {
            color = 'volcano';
          }
          return (
            <Tag color={color} key={tag}>
              {tag.toUpperCase()}
            </Tag>
          );
        })}
      </span>
    ),
  },
  {
    title: 'Action',
    key: 'action',
    render: (text, record) => (
      <span>
        <a>Invite {record.name}</a>
        <Divider type="vertical" />
        <a>Delete</a>
      </span>
    ),
  },
];

const data = [
  {
    key: '1',
    name: 'John Brown',
    age: 32,
    address: 'New York No. 1 Lake Park',
    tags: ['nice', 'developer'],
  },
  {
    key: '2',
    name: 'Jim Green',
    age: 42,
    address: 'London No. 1 Lake Park',
    tags: ['loser'],
  },
  {
    key: '3',
    name: 'Joe Black',
    age: 32,
    address: 'Sidney No. 1 Lake Park',
    tags: ['cool', 'teacher'],
  },
];
function List() {

  return (
    <div className={styles.normal}>
      <Table columns={columns} dataSource={data} />
    </div>
  );
}

function mapStateToProps() {
  return {};
}

export default connect(mapStateToProps)(List);

dva搭建项目实例_第5张图片

定义model

$ dva g model list

在这里插入图片描述

编辑list.js


export default {
  // 当前model的名称。
  // 整个应用的state,由多个小的model的state以namespace为key合成
  namespace: 'list',

  // 该model当前的状态。
  // 数据保存在这里,决定了视图层的输出
  state: {
    data: [],
  },

  // action处理器 处理同步动作,更新state
  reducers: {
    save(state, action) {
      return { ...state, ...action.payload }
    }
  },

  // Action处理器,处理异步动作
  effects: {
    *fetch({ payload }, { call, put }) {
      yield put({ type: 'save' })
    }
  },

  // 订阅事件 解决传值问题
  // 兄弟组件间通信不必再像使用props那种通过父组件来通信,
  // 多层组件之间通信也不必在一层一层的传递, 
  // 直接在触发事件的组件中发布消息 监听组件中订阅消息即可
  subscriptions: {
    setup({ dispatch, history }) {

    }
  },
};

使用connect绑定models

可以看到component List中末尾有这一行
在这里插入图片描述
model/list.js中的effects中添加:

    *getUser({ payload }, { call, put }) {
      const res = yield call(service.get);
      console.log(res);
    },

修改router/List.js

import React from 'react';
import { connect } from 'dva';
import styles from './List.css';
import { Table, Divider, Tag } from 'antd';
const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
    render: text => <a>{text}</a>,
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address',
  },
  {
    title: 'Tags',
    key: 'tags',
    dataIndex: 'tags',
    render: tags => (
      <span>
        {tags.map(tag => {
          let color = tag.length > 5 ? 'geekblue' : 'green';
          if (tag === 'loser') {
            color = 'volcano';
          }
          return (
            <Tag color={color} key={tag}>
              {tag.toUpperCase()}
            </Tag>
          );
        })}
      </span>
    ),
  },
  {
    title: 'Action',
    key: 'action',
    render: (text, record) => (
      <span>
        <a>Invite {record.name}</a>
        <Divider type="vertical" />
        <a>Delete</a>
      </span>
    ),
  },
];

// const data = [
//   {
//     key: '1',
//     name: 'John Brown',
//     age: 32,
//     address: 'New York No. 1 Lake Park',
//     tags: ['nice', 'developer'],
//   },
//   {
//     key: '2',
//     name: 'Jim Green',
//     age: 42,
//     address: 'London No. 1 Lake Park',
//     tags: ['loser'],
//   },
//   {
//     key: '3',
//     name: 'Joe Black',
//     age: 32,
//     address: 'Sidney No. 1 Lake Park',
//     tags: ['cool', 'teacher'],
//   },
// ];
function List({dispatch,data}){
  return (
    <div className={styles.normal}>
      <Table columns={columns} dataSource={data} />
    </div>
  );
}

function mapStateToProps(state) {
  return {
    data:state.list.data
  };
}

export default connect(mapStateToProps)(List);

dva搭建项目实例_第6张图片

获取数据

创建services/list.js
dva搭建项目实例_第7张图片编辑services/list.js,模拟后台数据处理

import request from '../utils/request';

const data = [
    {
        key: '1',
        name: '模拟数据1',
        age: 32,
        address: 'New York No. 1 Lake Park',
        tags: ['nice', 'developer'],
    },
    {
        key: '2',
        name: '模拟数据2',
        age: 42,
        address: 'London No. 1 Lake Park',
        tags: ['loser'],
    },
    {
        key: '3',
        name: '模拟数据3',
        age: 32,
        address: 'Sidney No. 1 Lake Park',
        tags: ['cool', 'teacher'],
    },
];

export function test() {
    return request('/users', {
        method: 'get'
    })
}

export function get() {
    saveUsers(data); // 存储在本地查看
    return data; // 模拟后台返回数据
}

export function add(values) {
    // 获取最新人员信息
    const users = queryUsers();
    values.key = Math.random();
    // 模拟后台处理新增的人员信息,直接添加到人员列表
    users.push(values);
    // 保存处理后最新的人员信息
    saveUsers(data); // 存储在本地查看
    return data; // 模拟后台返回数据
}

export function deleteUser(values) {
    // 获取最新的人员信息
    const users = queryUsers();

    // 模拟后台处理删除的人员信息,使用filter过滤掉已经删除的人员
    const newUsers = users.filter(item => item.key !== values.key);

    // 保存处理后最新的人员信息
    saveUsers(newUsers);  // 存储在本地,方便查看

    return newUsers;  // 模拟后台返回的数据

}

export function editUser(values) {

    // 获取最新的人员信息
    const users = queryUsers();

    // 模拟后台处理新增的人员信息,直接添加到人员列表里面
    const newUsers = users.map((item) => {

        if (item.key === values.key) { // 相等,代表这个人员信息已被修改,需要用新的人员消息替换旧的人员信息;
            return values;
        } else { // 不相等,代表这个人员信息未被修改,直接返回该人员信息; 
            return item;
        }

    });

    // 保存处理后最新的人员信息
    saveUsers(newUsers);  // 存储在本地,方便查看
    return newUsers;  // 模拟后台返回的数据

}

const saveUsers = (users) => {
    localStorage.setItem("users", JSON.stringify(users));
};

const queryUsers = () => {
    return JSON.parse(localStorage.getItem("users"));
};

models/list.jseffects中添加:

*getUser({ payload }, { call, put }) {
      const data = yield call(listService.get);
      yield put({ type: 'save', payload: { data } });

listService:import * as listService from ‘…/services/list’

routes/List.js中添加:

  useEffect(() => {
    dispatch({ type: 'list/getUser' })
  }, []);

dva搭建项目实例_第8张图片

添加新数据

修改route/List.js页面,增加新增按钮和点击事件

import React, { useEffect, useState } from 'react';
import { connect } from 'dva';
import styles from './List.css';
import { Table, Divider, Tag, Button, Modal, Form, Input, Row, Col } from 'antd';
const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
    render: text => <a>{text}</a>,
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address',
  },
  {
    title: 'Tags',
    key: 'tags',
    dataIndex: 'tags',
    render: tags => (
      <span>
        {tags.map(tag => {
          let color = tag.length > 5 ? 'geekblue' : 'green';
          if (tag === 'loser') {
            color = 'volcano';
          }
          return (
            <Tag color={color} key={tag}>
              {tag.toUpperCase()}
            </Tag>
          );
        })}
      </span>
    ),
  },
  {
    title: 'Action',
    key: 'action',
    render: (text, record) => (
      <span>
        <a>Invite {record.name}</a>
        <Divider type="vertical" />
        <a>Delete</a>
      </span>
    ),
  },
];


function List({ dispatch, data }) {
  useEffect(() => {
    dispatch({ type: 'list/getUser' })
  }, []);
  const [isModalOpen, setIsModalOpen] = useState(false);

  const showModal = () => {
    setIsModalOpen(true);
  };

  const handleOk = (values) => {
    console.log(values);
    setIsModalOpen(false);
  };

  const handleCancel = () => {
    setIsModalOpen(false);
  };
  return (
    <div className={styles.normal}>
      <Button type="primary" onClick={showModal}>
        新增
      </Button>
      <Modal title="Basic Modal" open={isModalOpen} footer={null} onOk={handleOk} onCancel={handleCancel}>
        <Form
          name="basic"
          labelCol={{ span: 4 }}
          wrapperCol={{ span: 20 }}
          autoComplete="off"
          onFinish={handleOk}
        >
          <Form.Item
            label="name"
            name="name"
            rules={[{ required: true, message: 'Please input your name!' }]}
          >
            <Input />
          </Form.Item>
          <Form.Item
            label="age"
            name="age"
            rules={[{ required: true, message: 'Please input your age!' }]}
          >
            <Input />
          </Form.Item>
          <Form.Item
            label="address"
            name="address"
            rules={[{ required: true, message: 'Please input your address!' }]}
          >
            <Input />
          </Form.Item>
          <Form.Item
            label="tags"
            name="tags"
            rules={[{ required: true, message: 'Please input your tags!' }]}
          >
            <Input />
          </Form.Item>
          <Form.Item >
            <Row>
              <Col span={12} >
                <Button type="primary" htmlType="submit">
                  确认
                </Button>
              </Col>
              <Col span={12}>
                <Button htmlType="button" onClick={handleCancel}>
                  取消
                </Button>
              </Col>
            </Row>


          </Form.Item>
        </Form>
      </Modal>
      <Table columns={columns} dataSource={data} />
    </div>
  );
}

function mapStateToProps(state) {
  return {
    data: state.list.data
  };
}

export default connect(mapStateToProps)(List);


修改提交方法

  const handleOk = (values) => {
    console.log(values);
    dispatch({
      type:'list/addUser',
      payload:values
    })
    setIsModalOpen(false);
  };

添加model中的effcet

    *addUser({payload},{call,put}){
      const data = yield call(listService.add,payload);
      yield put({ type: 'save', payload: { data } });
    }

你可能感兴趣的:(React,javascript,前端,npm)