Skip to content

Latest commit

 

History

History
291 lines (233 loc) · 8.48 KB

05-组件设计实践.md

File metadata and controls

291 lines (233 loc) · 8.48 KB

组件设计实践

准备

建议对照完整代码一起看 user-dashboard

按照之前快速上手的内容,我们可以使用 dva-cli 工具快速生成规范的目录,在命令行中输入:

$ mkdir myApp && cd myApp
$ dva init

现在,规范的样例模板我们已经有了,接下来我们一步一步添加自己的东西,看看如何完成我们的组件设计。

设置路由

在准备好了 dva 的基本框架以后,需要为我们的项目配置一下路由,这里首先设置 Users Router Container 的访问路径,并且在 /routes/ 下创建我们的组件文件 Users.jsx

// .src/router.js
import React, { PropTypes } from 'react';
import { Router, Route } from 'dva/router';
import Users from './routes/Users';

export default function({ history }) {
  return (
    <Router history={history}>
      <Route path="/users" component={Users} />
    </Router>
  );
};
// .src/routes/Users.jsx
import React, { PropTypes } from 'react';

function Users() {
  return (
    <div>User Router Component</div>
  );
}

Users.propTypes = {
};

export default Users;

其它路由可以自行添加,关于路由更多信息,可以查看 react-router 获取更多内容。

Users Container Component 的设计

基础工作都准备好了,接下来就开始设计 Users Container Component。在本项目中 Users Container 的表现为 Route Components(这也是 dva 推荐的结构划分),可以理解页面维度的容器,所以我们在 /routes/ 下加入 Users.jsx

我们采用自顶向下的设计方法,修改 ./src/routes/Users.jsx 如下:

// ./src/routes/Users.jsx
import React, { Component, PropTypes } from 'react';

// Users 的 Presentational Component
// 暂时都没实现
import UserList from '../components/Users/UserList';
import UserSearch from '../components/Users/UserSearch';
import UserModal from '../components/Users/UserModal';

// 引入对应的样式
// 可以暂时新建一个空的
import styles from './Users.less';

function Users() {

  const userSearchProps = {};
  const userListProps = {};
  const userModalProps = {};

  return (
    <div className={styles.normal}>
      {/* 用户筛选搜索框 */}
      <UserSearch {...userSearchProps} />
      {/* 用户信息展示列表 */}
      <UserList {...userListProps} />
      {/* 添加用户 & 修改用户弹出的浮层 */}
      <UserModal {...userModalProps} />
    </div>
  );
}

export default Users;

其中,UserSearchUserListUserModal 我们还未实现,不过我们可以暂时让他们输出一段话,表示占位,基本的结构表现的很清楚,Users Router Container 由这三个 Presentational Components 组成。(其中{...x}的用法可以参看es6

// ./src/components/Users/UserSearch.jsx
import React, { PropTypes } from 'react';
export default ()=><div>user search</div>;
// ./src/components/Users/UserList.jsx
import React, { PropTypes } from 'react';
export default ()=><div>user list</div>;
// ./src/components/Users/UserModal.jsx
import React, { PropTypes } from 'react';
export default ()=><div>user modal</div>;

现在如果你的本地环境是成功的,访问 http://127.0.0.1:8989/#/users 浏览器中看到:

image

需要注意的是,定义我们的组件一般有三种方式:

// 1. 传统写法
const App = React.createClass({});

// 2. es6 的写法
class App extends React.Component({});

// 3. stateless 的写法(我们推荐的写法)
const App = (props) => ({});

其中第1种是我们不推荐的写法,第2种是在你的组件涉及 react 的生命周期方法的时候采用这种写法,而第3种则是我们一般推荐的写法。详细内容可以参看Stateless Functions

在确定了最简陋的结构以后,接下来需要做的事情,就是完善 Users Container 中的组件,在这里我们优先实现 UserList 组件。

Userlist 组件

暂时放下<UserSearch /><UserModal />,先来看看<UserList />的实现,这是一个用户的展示列表,我们期望只需要把数据传入进去,修改 ./src/components/Users/UserList.jsx

// ./src/components/Users/UserList.jsx
import React, { Component, PropTypes } from 'react';

// 采用antd的UI组件
import { Table, message, Popconfirm } from 'antd';

// 采用 stateless 的写法
const UserList = ({
    total,
    current,
    loading,
    dataSource,
}) => {
  const columns = [{
    title: '姓名',
    dataIndex: 'name',
    key: 'name',
    render: (text) => <a href="#">{text}</a>,
  }, {
    title: '年龄',
    dataIndex: 'age',
    key: 'age',
  }, {
    title: '住址',
    dataIndex: 'address',
    key: 'address',
  }, {
    title: '操作',
    key: 'operation',
    render: (text, record) => (
      <p>
        <a onClick={()=>{}}>编辑</a>
        &nbsp;
        <Popconfirm title="确定要删除吗?" onConfirm={()=>{}}>
          <a>删除</a>
        </Popconfirm>
      </p>
    ),
  }];

	// 定义分页对象
  const pagination = {
    total,
    current,
    pageSize: 10,
    onChange: ()=>{},
  };

  return (
    <div>
      <Table
        columns={columns}
        dataSource={dataSource}
        loading={loading}
        rowKey={record => record.id}
        pagination={pagination}
      />
    </div>
  );
}

export default UserList;

为了方便起见,我们这里使用一个优秀的UI组件库 antdantd 提供了 table 组件,可以让我们方便的展示相关数据,具体使用方式可以参看其文档。

需要注意的是,由于我们采用了 antd,所以我们需要在我们的代码中添加样式,可以在 ./src/index.jsx 中添加一行:

import 'antd/dist/antd.css';

这样我们使用的的 antd 组件就可以展示出样子了:

image

其中我们发现,在我们设计 UserList 的时候,需要将分页信息 total、current 以及加载状态信息 loading 也传入进来,所以现在使用 UserList 就需要像这样:

<UserList
	current={current}
	total={total}
	dataSource={list}
	loading={loading}
/>

接下来,我们回到 Users Router Container 模拟一些静态数据,传入 UserList ,让其展现数据。

给 UserList 添加静态数据

// ./src/routes/Users.jsx
import React, { Component, PropTypes } from 'react';

// Users 的 Presentational Component
// 暂时都没实现
import UserList from '../components/Users/UserList';
import UserSearch from '../components/Users/UserSearch';
import UserModal from '../components/Users/UserModal';

// 引入对应的样式
// 可以暂时新建一个空的
import styles from './Users.less';

function Users() {

  const userSearchProps={};
  const userListProps={
    total: 3,
    current: 1,
    loading: false,
    dataSource: [
      {
        name: '张三',
        age: 23,
        address: '成都',
      },
      {
        name: '李四',
        age: 24,
        address: '杭州',
      },
      {
        name: '王五',
        age: 25,
        address: '上海',
      },
    ],
  };
  const userModalProps={};

  return (
    <div className={styles.normal}>
      {/* 用户筛选搜索框 */}
      <UserSearch {...userSearchProps} />
      {/* 用户信息展示列表 */}
      <UserList {...userListProps} />
      {/* 添加用户 & 修改用户弹出的浮层 */}
      <UserModal {...userModalProps} />
    </div>
  );
}

Users.propTypes = {
  users: PropTypes.object,
};

export default Users;

传入了静态数据以后,组件的表现如下:

image|400

组件设计小结

虽然我们上面实现的代码很简单,但是已经包含了组件设计的主要思路,可以看到 UserList 组件是一个很纯粹的 Presentation Component,所需要的数据以及状态是通过 Users Router Component 传递的,我们现在还是用的静态数据,接下来我们来看看如何在 model 创建 reducer 来将我们的数据抽象出来。

下一步,进入添加Reducers