At that time, I wanted to improve my React ability. Just recently read god three in the gold diggingReact Hooks and Immutable data streams. So, this summer, listen to god’s Song, with this little volume and a simple copy of Geek Time using React +hooks.

In my opinion, for a good front-end engineering lion, it’s not just about being proficient in the front end, but also about the back-end processes. In this way, it will be very smooth when docking with the back end in the future. Here, I recommend using mocker-API to realize simulation data, which is convenient for docking with the back end.

preface

In this section, you need to do the following,

  1. Pull down refresh,
  2. Pull up to load more.
  3. Processing of data paging back.

We can directly use the Better Scroll encapsulated in the Divine Ternary project.

Let’s start with the results

Preview the address

Partial project structure

| - pages/page/folder

| | - forum/folder/lecture hall page

| | | - course/page/course

|   |   |   |-- Forum.css

|   |   |   |-- Forum.jsx

|   |   |   |-- style.js

| | | | - store/store/course page

| | | | -- actionCreators. Js / / action file

| | | | - the js / / constant definition file

| | | | -- index. Js file / / store entrance

| | | | -- reducer. Js / / reducer for file

Copy the code

Understanding the project structure is the first and most important step in learning the React architecture idea. In my project, the Pages folder holds the home folder for each page. Here we mainly look at forum namely the realization of this part of the lecture hall. Through reading the project of Shensanyuan, I understand that store can be established on the page surface, which makes data access more concise and store design ideas more clear.

The front-end code

Lecture page analysis

  • forum.jsx

In the forum. JSX file, the encapsulated Better-Scroll code can be directly used to monitor the drop-down and pull-up events of the page. The pulldown function listens for the pulldown action to implement a pulldown refresh. The pullup function listens for pull-up action to implement pull-up loading. The handlePullUp and handlePullDown functions are passed to the common component Scroll via props.

  1. The browser calls handlePullDown when it listens for an event like a pulldown pull, The handlePullDown function in turn calls the pullDownRefresh() function deconstructed from props, which dispatches two actions, changeListOffset(0) and getInfoList(). ChangeListOffset (0) is used to set listOffset in the store to 0, and getInfoList() is used to get the details list data.

The code is as follows:

import React, { useEffect, memo } from 'react';

import { connect } from 'react-redux';

import * as actionTypes from './store/actionCreators';

import ForumList from '.. /.. /.. /components/ForumList/ForumList';

import Loading from '.. /.. /.. /common/loading/Loading';

import Scroll from '.. /.. /.. /common/scroll/Scroll';

import { ListContainer } from './style';

import { forceCheck } from 'react-lazyload';

import './Forum.css';

import { renderRoutes } from 'react-router-config';



function Forum(props{

    const { route, pathList, directionList, infoList, enterLoading, pageCount, pullUpLoading, pullDownLoading } = props;

    const { getForumListDataDispatch, getInfoListDataDispatch, pullUpRefresh, pullDownRefresh } = props;

    

    const handlePullUp = (a)= > {

        pullUpRefresh();

    };



    const handlePullDown = (a)= > {

        pullDownRefresh();

    };



    useEffect((a)= > {

        // If no data is requested once

        if(! pathList.toJS().length || ! directionList.toJS().length) {

            getForumListDataDispatch();

        }

        if(! infoList.toJS().length) {

            getInfoListDataDispatch();

        }

    }, [getForumListDataDispatch, getInfoListDataDispatch, pathList, directionList, infoList])



    return (

        <div className="forum">

            <ListContainer>

                <Scroll

                    onScroll={forceCheck}

                    pullUp={handlePullUp}

                    pullDown={handlePullDown}

                    pullUpLoading={pullUpLoading}

                    pullDownLoading={pullDownLoading}

// pullDown, listen to the pulldown, can realize the pulldown refresh;

// pullup, listen to pullup, can realize pullup load;

                >

                    <div>

                        <div className="forum-xw">

                            <ForumList infoList={infoList} />

                        </div>

                    </div>

                </Scroll>

            </ListContainer>

<Loading Loading={enterLoading} title=" Loading... />

{/* reconfigure routes */}

            {renderRoutes(route.routes)}

        </div>)

}



const mapStateToProps = (state) => ({

    pathList: state.forum.pathList,

    directionList: state.forum.directionList,

    infoList: state.forum.infoList,

    enterLoading: state.forum.enterLoading,

    pageCount: state.forum.pageCount,

    pullUpLoading: state.forum.pullUpLoading,

    pullDownLoading: state.forum.pullDownLoading 

})



const mapDispatchToProps = (dispatch) => {

    return {



        getForumListDataDispatch() {

            dispatch(actionTypes.getPathList())

            dispatch(actionTypes.getDirectionList())

        },



        getInfoListDataDispatch() {

            dispatch(actionTypes.getInfoList())

        },



// Slide to the bottom of the refresh section

        pullUpRefresh() {

            dispatch(actionTypes.changePullUpLoading(true));

            dispatch(actionTypes.refreshMoreInfoList());

        },

        

// Top drop refresh

        pullDownRefresh() {

            dispatch(actionTypes.changePullDownLoading(true));

            dispatch(actionTypes.changeListOffset(0));

            dispatch(actionTypes.getInfoList());

        }

    }

}

export default connect(mapStateToProps, mapDispatchToProps)(memo(Forum))

Copy the code

The design of the store

  • The js file
export const CHANGE_INFOS = 'CHANGE_INFOS';

export const CHANGE_LIST_OFFSET = 'home/singers/CHANGE_LIST_OFFSET'// Data paging constant

export const CHANGE_ENTER_LOADING = 'CHANGE_ENTER_LOADING';

export const CHANGE_PULLUP_LOADING = 'home/singers/PULLUP_LOADING'// Pull constant

export const CHANGE_PULLDOWN_LOADING = 'home/singers/PULLDOWN_LOADING'// Drop constant

Copy the code

The constants.js file is responsible for defining and exporting constants.

  • reducer.js
import * as actionTypes from './constants';



const defaultState = {

    // A page has only one loading value

    // All course data

    infoList:[],

    enterLoading:true./ / load

    pullUpLoading: false.// Pull up load

    pullDownLoading: false.// Drop refresh

    listOffset: 0.// Request list offset is a number

}



export default (state = defaultState, action) => {

    switch(action.type) {

        case actionTypes.CHANGE_INFOS:

            return { ...state, infoList: action.data}

        case actionTypes.CHANGE_ENTER_LOADING:

            return { ...state, enterLoading: action.data}

        case actionTypes.CHANGE_LIST_OFFSET:

            return { ...state, listOffset: action.data}

        case actionTypes.CHANGE_PULLUP_LOADING:

            return { ...state, pullUpLoading: action.data}

        case actionTypes.CHANGE_PULLDOWN_LOADING:

            return { ...state, pullDownLoading: action.data}

        default:

            return state

    }

}

Copy the code

There is only one state corresponding to the update of return state and accept state of the reducer pure function.

  • actionCreators.js
// Take charge of data requests

import * as actionTypes from './constants';

// Request the interface file

import { getInfoListRequest} from '.. /.. /.. /.. /api/request';



export const changeListOffset = (data) = > ({

    type: actionTypes.CHANGE_LIST_OFFSET,

    data

  });



/ / loading approach

export const changeEnterLoading = (data) = > ({

    type: actionTypes.CHANGE_ENTER_LOADING,

    data

})



// Slide the bottom loading

export const changePullUpLoading = (data) = > ({

    type: actionTypes.CHANGE_PULLUP_LOADING,

    data

  });

  

// Top dropdown refresh loading

export const changePullDownLoading = (data) = > ({

    type: actionTypes.CHANGE_PULLDOWN_LOADING,

    data

  });



export const changeInfoList = (data) = > ({

    type: actionTypes.CHANGE_INFOS,

    data

})



// Get details list data

export const getInfoList = (a)= > {

    return (dispatch, getState) = > {

        // Get the offset from the original store

        const offset = getState().forum.listOffset;



        // The offset is passed to the interface request

        getInfoListRequest(offset).then(res= > {

            const data = res.infos

            dispatch(changeInfoList(data));

            // Get data EnterLoading to false

            dispatch(changeEnterLoading(false));

            dispatch(changePullDownLoading(false));

            dispatch(changeListOffset(data.length));

        })

        // If you get the wrong data

        .catch((a)= > {

            console.log('Detail list data transfer error')

        })

    }

}



// Load more data

export const refreshMoreInfoList = (a)= > {

    return (dispatch, getState) = > {

     // Get the original listOffset and infoList data

        const offset = getState().forum.listOffset;

        const infos = getState().forum.infoList;

        getInfoListRequest(offset).then(res= > {

            // Let the current infOS and the newly requested INFOS expand and concatenate into a new data using the extended operator;

            const data = [...infos, ...res.infos]

            dispatch(changeInfoList(data));

            dispatch(changePullUpLoading(false));

            dispatch(changeListOffset(data.length));

        })

        .catch((a)= > {

            console.log('Detail list data transfer error')

        })

    }

}

Copy the code

Analysis of ideas:

When fetching detail list data, i.e. calling getInfoList, we first need to fetch the offset from the original store and make a request. Once we get the data successfully, we set the drop-down refresh to false and set the listoffset offset to the length of the received data.

When we need to load more data, we need to use getState to get the original listOffset and infoList data first. After getting the data, we will combine the old data with the new data to get a new data. Then changeInfoList(data) changes the store data, so that our previous data will not be lost. And set listoffset to the length of the new data to ensure proper data paging. Let’s go to getInfoList in the Store

export const getInfoList = (a)= > {

    return (dispatch, getState) = > {

        // Get the offset from the original store

        const offset = getState().forum.listOffset;



        // The offset is passed to the interface request

        getInfoListRequest(offset).then(res= > {

            const data = res.infos

            dispatch(changeInfoList(data));

            // Get data EnterLoading to false

            dispatch(changeEnterLoading(false));

            dispatch(changePullDownLoading(false));

            dispatch(changeListOffset(data.length));

        })

        // If you get the wrong data

        .catch((a)= > {

            console.log('Detail list data transfer error')

        })

    }

}

Copy the code

This function returns a function that takes two arguments, dispatch, to modify the contents of the store, and getState, to get the contents of the Store. We first get listOffset from the store. The function gets the result. Then it changes the data in the store and sets EnterLoading to false. PullDownLoading to false Change listoffset in the Store to the length of the data to be obtained.

Request interface file

  • config.js
import axios from 'axios';

// AxiOS is recommended for better compatibility



export const baseUrl = "http://localhost/data"// The global backend API prefix



const axiosInstance = axios.create({

    baseURL:baseUrl

})



// Reply processing

axiosInstance.interceptors.response.use(

    res= > res.data,

    err => {

        console.log(err, 'Network error')

    }

)



export { axiosInstance }

Copy the code
  • request.js
// Get data about the learning path and course direction



import { axiosInstance } from './config';



// Get data from all courses

export const getInfoListRequest = count= > {

    return axiosInstance.get(`/infos? offset=${count}`);

}

Copy the code

The back-end code

const infos = require('./data/infos.json');



module.exports = {

    // Paging data

    'GET /data/infos'(req, res) = > {

        // Get the offset argument passed in

        const { offset = 0 } = req.query;

        // Use Number to convert to Number type

        const data = infos.slice(Number(offset) , Number(offset)  + 10);

        res.json({

            "infos":data});

    }

}

Copy the code

The user swipes the screen to trigger an event, and the offset passed in can be deconstructed by req.query. If it is not passed in, it defaults to 0. The corresponding data is then returned.

Entry file index.js

const express = require('express');

const path = require('path');

const apiMocker = require('mocker-api');



const app = express();



apiMocker(app, path.resolve('./mocker/mocker.js'))

app.listen(8080);

Copy the code

The above is the main content of this section, personal technology is not good, the project has defects, welcome to dig friends correct, I will improve, the following is the source of the project. Github React-Geek-time project source code.

The author is preparing autumn recruit, welcome everybody big guy to discuss together, refueling together!