3、Mock 数据

接下来我们来实现刷新和加载更多的功能。在实现这个功能之前,我们首先将数据改造成 mock 的方式,毕竟在一个实际的项目里,这些数据都应该是从后端请求得到的。

对于 mock 我们推荐使用 YApi,它是我们开发的 API 管理平台,她提供了全方位的 API 管理功能,让团队的合作更加的高效,具体的使用可以参考 YApi 使用手册。这里我们已经建好了一个接口,它的 mock 地址为http://yapi.corp.qunar.com/mock/1239/api/list,接下来我们把请求这个接口所返回的数据作为列表页 List 组件的数据源。

首先我们修改下 reducers,增加覆盖更新(UPDATE_LIST,对应下拉刷新)和增量更新(CONCAT_LIST,对应加载更多)的 Action type:

  1. export default (state = {
  2. list: []
  3. }, action) => {
  4. const { type, payload } = action;
  5. switch (type) {
  6. case 'UPDATE_LIST': {
  7. return {
  8. ...state,
  9. list: payload.data
  10. }
  11. break;
  12. }
  13. case 'CONCAT_LIST': {
  14. return {
  15. ...state,
  16. list: state.list.concat(payload.data)
  17. }
  18. break;
  19. }
  20. default: {
  21. console.log(state);
  22. return state;
  23. }
  24. }
  25. };

接下来编写 actions。在 src 目录下新建 actions 目录,在新建目录下创建 index.js:

  1. export const fetchList = page => dispatch => (
  2. fetch('http://yapi.corp.qunar.com/mock/1239/api/list')
  3. .then(res =>res.json()
  4. .then(data => {
  5. if (page === 1) {
  6. return dispatch({
  7. type: 'UPDATE_LIST',
  8. payload: data
  9. })
  10. } else {
  11. return dispatch({
  12. type: 'CONCAT_LIST',
  13. payload: data
  14. })
  15. }
  16. }
  17. ))
  18. );

将 action 方法绑定到列表页组件中。

  1. import { fetchList } from '../../actions';
  2. ...
  3. const mapStateToProps = state => ({
  4. list: state.list
  5. });
  6. const mapDispatchToProps = dispatch => ({
  7. fetchList: params => dispatch(fetchList(params))
  8. });
  9. export default connect(
  10. mapStateToProps,
  11. mapDispatchToProps
  12. )(Detail);

在组件中调用绑定的 action 方法以触发请求:

  1. class Detail extends Component {
  2. constructor() {
  3. super();
  4. this.page = 1;
  5. }
  6. refresh() {
  7. const { fetchList } = this.props;
  8. this.page = 1;
  9. fetchList(this.page);
  10. }
  11. fetch() {
  12. const { fetchList } = this.props;
  13. fetchList(++this.page);
  14. }
  15. componentDidMount() {
  16. this.fetch(this.page);
  17. }
  18. render() {
  19. const { list } = this.props;
  20. if (list && list.length > 0) {
  21. return (
  22. <div className="yo-flex">
  23. <Header title="列表页" right={{
  24. title: '点我',
  25. onTap: () => alert('hello')
  26. }}/>
  27. <List
  28. ref="list"
  29. extraClass="flex m-list"
  30. dataSource={list}
  31. renderItem={(item, i) => <div>{ i + ':' + item.text}</div> }
  32. infinite={true}
  33. infiniteSize={20}
  34. itemHeight={44}
  35. usePullRefresh={true}
  36. onRefresh={() => {
  37. setTimeout(() => {
  38. this.refresh();
  39. this.refs.list.stopRefreshing(true);
  40. }, 500);
  41. }}
  42. useLoadMore={true}
  43. onLoad={() => {
  44. setTimeout(() => {
  45. this.fetch();
  46. this.refs.list.stopLoading(true);
  47. }, 500);
  48. }}
  49. itemExtraClass={(item, i) => {
  50. return 'item ' + i;
  51. }}
  52. onItemTap={(item, i, ds) => {
  53. yoHistory.push('/detail');
  54. }}
  55. />
  56. </div>
  57. );
  58. } else {
  59. return null;
  60. }
  61. }
  62. }

现在列表页组件的数据就完全交给 Redux 来管理了,整个组件已经不再有自己的 state 了。

当然你也可以用 YKit 来实现数据的 mock 功能,具体可见 YKit:代理工具 的Mock服务章节。