2-8 实现加载更多功能

加载更多,就在在首页的底部有一个加载更多按钮,当点击它时,就能加载更多的 list 。

由于它主要是加载更多的 list,因此,我们把加载更多放到 src/pages/home 下的 List.js 组件中。

下面是 List.js 代码。

import React, {Component} from 'react';
import { connect } from 'react-redux';
import { ListItem, ListInfo, LoadMore } from '../style';

class List extends Component {
    render () {
        const { articleList } = this.props;
        return (
            <div>
                { 
                    articleList.map( (item) => {
                        return (
                            <ListItem key={item.get('id')}>
                                <img
                                    className='pic'
                                    src={item.get('imgURL')}
                                    alt=''
                                />
                                <ListInfo>
                                    <h3 className='title'>{item.get('title')}</h3>
                                    <p className='desc'>{item.get('desc')}</p>
                                </ListInfo>
                            </ListItem>
                        )
                    } )
                }
                <LoadMore>更多文字</LoadMore>
            </div>
        )
    }
}

const mapStateToProps = (state) => {
    return {
        articleList: state.get("home").get("articleList")
    }
}

export default connect(mapStateToProps, null)(List);

下面是src/pages/home 下的 style.js 中添加的内容

export const LoadMore = styled.div`
    width: 100%;
    height: 40px;
    margin: 30px 0;
    line-height: 40px;
    background: #a5a5a5;
    text-align: center;
    border-radius: 20px;
    color: #fff;
    cursor: pointer;
`;

然后,我们给这个小组件一个点击事件,并使它的点击事件派发一个action,如下

import React, {Component} from 'react';
import { connect } from 'react-redux';
import { ListItem, ListInfo, LoadMore } from '../style';
import { actionCreators } from '../store';

class List extends Component {
    render () {
        const { articleList, getMoreList } = this.props;
        return (
            <div>
                { 
                    articleList.map( (item) => {
                        return (
                            <ListItem key={item.get('id')}>
                                <img
                                    className='pic'
                                    src={item.get('imgURL')}
                                    alt=''
                                />
                                <ListInfo>
                                    <h3 className='title'>{item.get('title')}</h3>
                                    <p className='desc'>{item.get('desc')}</p>
                                </ListInfo>
                            </ListItem>
                        )
                    } )
                }
                <LoadMore onClick={getMoreList}>更多文字</LoadMore>
            </div>
        )
    }
}

const mapStateToProps = (state) => {
    return {
        articleList: state.get("home").get("articleList")
    }
};

const mapDispatchToProps = (dispatch) => {
    return {
        getMoreList () {
            dispatch(actionCreators.getMoreList());
        }
    }
};

export default connect(mapStateToProps, mapDispatchToProps)(List);

然后,我们去 actionCreators 中去创建这个action ,如下。

我们定义这个的请求接口为 “/api/homeList.json” 。

并在 src/mockdata.js 文件中添加这个 mock 数据如下。

Mock.mock("/api/homeList.json", {
  "success" : true,
  "data": {
    "articleList": [{
      "id": 3,
      "title": "这是标题3",
      "desc": "这个段落的概要的内容3。。。",
      "imgURL": "//upload-images.jianshu.io/upload_images/13910150-3c33a8d64aa623bc.png?imageMogr2/auto-orient/strip|imageView2/1/w/360/h/240"
    },{
      "id": 4,
      "title": "这是标题4",
      "desc": "这个段落的概要的内容4。。。",
      "imgURL": "//upload-images.jianshu.io/upload_images/13910150-3c33a8d64aa623bc.png?imageMogr2/auto-orient/strip|imageView2/1/w/360/h/240"
    }]
  }
});

然后我们在actionCreators.js 中添加action

import axios from 'axios';
import { fromJS } from 'immutable';
import * as actionTypes from './actionTypes';

const changeHomeData = (result) => ({
    type: actionTypes.CHANGE_HOME_DATA,
    topicList: result.topicList,
    articleList: result.articleList,
    recommendList: result.recommendList
});

const addHomeList = (result) => ({
    type: actionTypes.ADD_ARTICLE_LIST,
    articleList: fromJS(result.articleList)
})

export const getHomeInfo = () => {
    return (dispatch) => {
        axios.get("/api/home.json").then((res) => {
            const result = res.data.data;
            const action = changeHomeData(result);
            dispatch(action);
        });
    }
}

export const getMoreList = () => {
    return (dispatch) => {
        axios.get("/api/homeList.json").then((res) => {
            const result = res.data.data;
            const action = addHomeList(result);
            dispatch(action);
        })
    }
}

添加一个actionType,actionTypes.js 如下

export const CHANGE_HOME_DATA = 'home/change_home_data';
export const ADD_ARTICLE_LIST = 'home/add_article_list';

然后在reducer (src/pages/home/store/reducer.js) 中增加一个case,如下。

import { fromJS } from 'immutable';
import * as actionTypes from './actionTypes';

const defaultState = fromJS({
    topicList: [],
    articleList: [],
    recommendList: []
});

export default (state = defaultState, action) => {
    switch (action.type) {
        case actionTypes.CHANGE_HOME_DATA:
            return state.merge({
                "topicList": fromJS(action.topicList),
                "articleList": fromJS(action.articleList),
                "recommendList": fromJS(action.recommendList)
            });
        case actionTypes.ADD_ARTICLE_LIST:
            return state.set("articleList", state.get("articleList").concat(action.articleList));
        default:
            return state;
    }
}

好的。

然后有一点,在实际开发中,我们是会把点击加载更多List 的数据做分页的。点击一次,就要告诉后端要第几页的数据。

下面就来实现一下这个分页。

首页在src/pages/home/store/reducer 中新建一个数据项 articlePage 默认值为 1。

import { fromJS } from 'immutable';
import * as actionTypes from './actionTypes';

const defaultState = fromJS({
    topicList: [],
    articleList: [],
    recommendList: [],
    articlePage: 1
});

export default (state = defaultState, action) => {
    switch (action.type) {
        case actionTypes.CHANGE_HOME_DATA:
            return state.merge({
                "topicList": fromJS(action.topicList),
                "articleList": fromJS(action.articleList),
                "recommendList": fromJS(action.recommendList)
            });
        case actionTypes.ADD_ARTICLE_LIST:
            return state.set("articleList", state.get("articleList").concat(action.articleList));
        default:
            return state;
    }
}

然后,回到src/pages/home/components 下的 List.js 我们要在组件中获取这个数据。

import React, {Component} from 'react';
import { connect } from 'react-redux';
import { ListItem, ListInfo, LoadMore } from '../style';
import { actionCreators } from '../store';

class List extends Component {
    render () {
        const { articleList, getMoreList, articlePage } = this.props;
        return (
            <div>
                { 
                    articleList.map( (item) => {
                        return (
                            <ListItem key={item.get('id')}>
                                <img
                                    className='pic'
                                    src={item.get('imgURL')}
                                    alt=''
                                />
                                <ListInfo>
                                    <h3 className='title'>{item.get('title')}</h3>
                                    <p className='desc'>{item.get('desc')}</p>
                                </ListInfo>
                            </ListItem>
                        )
                    } )
                }
                <LoadMore onClick={ () => getMoreList(articlePage)}>更多文字</LoadMore>
            </div>
        )
    }
}

const mapStateToProps = (state) => {
    return {
        articleList: state.get("home").get("articleList"),
        articlePage: state.get("home").get("articlePage")
    }
};

const mapDispatchToProps = (dispatch) => {
    return {
        getMoreList (page) {
            dispatch(actionCreators.getMoreList(page));
        }
    }
};

export default connect(mapStateToProps, mapDispatchToProps)(List);

然后在 src/pages/home/store 下的 actionCreators.js 中修改一下。

import axios from 'axios';
import { fromJS } from 'immutable';
import * as actionTypes from './actionTypes';

const changeHomeData = (result) => ({
    type: actionTypes.CHANGE_HOME_DATA,
    topicList: result.topicList,
    articleList: result.articleList,
    recommendList: result.recommendList
});

const addHomeList = (result, page) => ({
    type: actionTypes.ADD_ARTICLE_LIST,
    articleList: fromJS(result.articleList),
    page: page
})

export const getHomeInfo = () => {
    return (dispatch) => {
        axios.get("/api/home.json").then((res) => {
            const result = res.data.data;
            const action = changeHomeData(result);
            dispatch(action);
        });
    }
}

export const getMoreList = (page) => {
    return (dispatch) => {
        axios.get("/api/homeList.json?page=" + page).then((res) => {
            const result = res.data.data;
            const action = addHomeList(result, page + 1);
            dispatch(action);
        })
    }
}

然后,我们修改一下 src/pages/home/store 下的reducer,如下。

import { fromJS } from 'immutable';
import * as actionTypes from './actionTypes';

const defaultState = fromJS({
    topicList: [],
    articleList: [],
    recommendList: [],
    articlePage: 1
});

export default (state = defaultState, action) => {
    switch (action.type) {
        case actionTypes.CHANGE_HOME_DATA:
            return state.merge({
                "topicList": fromJS(action.topicList),
                "articleList": fromJS(action.articleList),
                "recommendList": fromJS(action.recommendList)
            });
        case actionTypes.ADD_ARTICLE_LIST:
            return state.merge({
                "articleList": state.get("articleList").concat(action.articleList),
                "articlePage": action.page
            })
        default:
            return state;
    }
}

Done.

猜你喜欢

转载自blog.csdn.net/purple_lumpy/article/details/89312610
2-8