Based on Taro framework

Function page configuration

function TestPage() {
}
TestPage.config = {
// Configure the applet page here
}
export default TestPage
Copy the code

Function component configuration

function TestCom(props) {
}
TestCom.options = {
    addGlobalClass: true
}
export default TestCom
Copy the code

The data load

const [list, setList] = useState([])
useEffect( async() = > {let data = await getData()
    setList(data)
}, [])// The null array emulates the componentDidMount function
Copy the code

Write a list to load components

Functional analysis

  • Empty state
  • The drop-down refresh
  • Pull on loading
  • Loading completion prompt
  • Load the closure

Implementation scheme

  • Use the pull-down refresh and pull-up load functions of applets
  • Abstract null-state components
  • Custom effect abstract loading scheme

List component code 1.0

import {View} from "@tarojs/components";
import Empty from ".. /empty";

function List(props) {
    const { listTotal, listLength, emptyTip, children } = props
    let isEmpty = listLength === 0
    let isLast = listLength >= listTotal
    return (
        <View>{children// list contents} {isEmpty// display && when the list isEmpty<Empty title={emptyTip} />} {! IsEmpty &&islast // display && when the non-empty state is loaded<View className='paddingY30 color-5 font-size-4 text-align-center'>I have my limits, too</View>
            }
        </View>
    )
}

List.options = {
    addGlobalClass: true
}

export default List
Copy the code

UseGetList 1.0 implements drop-down loading


import Taro, {useEffect, useReachBottom, useState} from "@tarojs/taro";

export default function useGetList(getList) {// The received data loading method is a parameter
    if(! getList)return []
    const [list, setList] = useState([]);// List data
    const [page, setPage] = useState(1);/ / list page
    useEffect(async() = > {try {
            let {list: listGet} = await getList(page)
            let newList =  page === 1 ? listGet : [...list, ...listGet]
            setList(newList)// Update the list
        } catch (e) {
            console.log(e)
        }
    }, [page])// execute when the page number changes

    useReachBottom(() = > {
        let pageMore = page + 1
        setPage(pageMore)
    })
    return list
}
Copy the code

UseGetList 1.1 implements traffic interception during loading and traffic interception after loading

The default backend returns the total number of lists, not the backend


import Taro, {useEffect, useReachBottom, useState} from "@tarojs/taro";

export default function useGetList(getList) {
    if(! getList)return []
    const [list, setList] = useState([]);
    const [page, setPage] = useState(1);
    const [count, setCount] = useState(null); // Total number of lists
    let loading = false // Check whether the load is in progress
    useEffect(async() = > {let isLast = typeof count === 'number' && list.length >= count // Check whether the load is complete
        let isStop = loading || isLast // Stop or not: Loading or pull-down loading is complete
        if(! isStop) { loading =true
            try {
                let {list: listGet, count: countGet} = await getList(page) // The default backend returns the total number of lists
                let newList =  page === 1? listGet : [...list, ...listGet] setList(newList) countGet ! == count && setCount(countGet)// Update the total number of lists
            } catch (e) {
                console.log(e)
            }
            setTimeout(() = > {
                loading = false // Reset the loading state
            }, 0)
        }
    }, [page])// execute when the page number changes

    useReachBottom(() = > {
        let pageMore = page + 1
        setPage(pageMore)
    })
    return list
}
Copy the code

UseGetList 2.0 implements drop-down refresh

Consider the need to refresh when page=1

At the same time, pull-down refresh and up-load belong to different loading types

So add a parameter — load type type as a condition for performing the useEffect callback

import Taro, {useEffect, usePullDownRefresh, useReachBottom, useState} from "@tarojs/taro";

export default function useGetList(getList) {
    if(! getList)return []
    const [page, setPage] = useState(1);
    const [list, setList] = useState([]);
    const [count, setCount] = useState(null);
    const [type, setType] = useState('load');// Load type,' load','refresh', etc
    let loading = false
    useEffect(async() = > {let isLast = typeof count === 'number' && list.length >= count
        let isLoadMore = type === 'load'// Check whether it is a drop-down load
        let isStop = loading || (isLoadMore && isLast)// Loading or pull-down loading is complete -- intercept
        if(! isStop) { loading =true
            try {
                let {list: listGet, count: countGet} = await getList(page)
                let newList =  page === 1? listGet : [...list, ...listGet] setList(newList) countGet ! == count && setCount(countGet) }catch (e) {
                console.log(e)
            }
            setTimeout(() = > {
                type === 'refresh' && Taro.stopPullDownRefresh() // The refresh drop-down stops
                loading = false
            }, 0)
        }

    }, [page, type]) // execute when page count changes or load type changes

    useReachBottom(() = > {
        let pageMore = page + 1setPage(pageMore) type ! = ='load' && setType('load') // Reset the loading state
    })

    usePullDownRefresh(() = >{ // Note that the page needs to be configured to allow refreshing
        setType('refresh') // Change the loading statepage ! = =1 && setPage(1)})return [list, count]
}
Copy the code
Index.config = {
    navigationBarTitleText: 'Test page'.enablePullDownRefresh: true // Page configuration drop-down refresh
}
Copy the code

The useEffect callback is re-executed by a pull-up load to update the page value

Drop down refresh to update the type value to re-execute the useEffect callback

At this point the list-loading component of the applet is ready to use


Using the example

import { View } from "@tarojs/components";
import DeviceCard from ".. /.. /components/device/deviceCard";
import List from ".. /.. /components/list";
import useGetList from ".. /.. /effects/useGetList";

// This function can be extracted into the backend request file
async function getDevices(page) {
    let list =  [
        {
            image: 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3744924158, & FM = 26 & gp = 0. 1824985192 JPG'.title: '1 How to easily in Coinicgame'.content: 'Vimason automatic sealing machine commercial automatic continuous heat sealing machine from Yamaha'.id: 1
        },
        {
            image: 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3744924158, & FM = 26 & gp = 0. 1824985192 JPG'.title: '2 How to easily in Coinicgame'.content: 'Vimason automatic sealing machine commercial automatic continuous heat sealing machine from Yamaha'.id: 2}]return {list, count: 24}}function Index() {
    const [list , count] = useGetList(getDevices, null)
    return (
        <View className='padding-bottom20'>
            <List length={list ? list.length : null}
                  count={count}>
                <View className='marginX20 flex-wrap'>
                    {
                        list && list.length && list.map((device,index) => (
                            <DeviceCard key={device.name + index}
                                        device={device} />))}</View>
            </List>
        </View>
    )
}

Index.config = {
    navigationBarTitleText: 'Test Equipment List'.enablePullDownRefresh: true
}

export default Index

Copy the code

The next thing to do is make it work better

The optimization goal

  • The list component supports receiving list subcomponents as parameters

Toss about for a long time did not succeed, function component novice

  • Extended list data filtering capabilities – search, filter

UseGetList 3.0 Adds the search and filtering function

import Taro, {useEffect, usePullDownRefresh, useReachBottom, useState} from "@tarojs/taro";
// Expose screen order update method
function createUseFilter(setPage, setType, setFilter) {
    return (filter) = > {
        setPage(1)
        setType('search')
        setFilter(filter)
    }
}
export default function useGetList(getList) {
    if(! getList)return []
    const [list, setList] = useState([]);
    const [count, setCount] = useState(null);
    const [page, setPage] = useState(1);
    const [type, setType] = useState('load');
    const [filter, setFilter] = useState({}); // Add screen order condition
    let loading = false
    useEffect(async() = > {let isLast = typeof count === 'number' && list.length >= count
        let isLoadMore = type === 'load'
        let isStop = loading || (isLoadMore && isLast)
        if(! isStop) { loading =true
            try {
                let {list: listGet, count: countGet} = await getList(page, filter) // Pass in the filter criteria
                let newList =  page === 1? listGet : [...list, ...listGet] setList(newList) countGet ! == count && setCount(countGet) }catch (e) {
                console.log(e)
            }
            type === 'refresh' && Taro.stopPullDownRefresh()
            setTimeout(() = > {
                loading = false
            }, 0)
        }

    }, [page, type, filter])
    useReachBottom(() = > {
        let pageMore = page + 1
        setPage(pageMore)
        setType('load')
    })
    usePullDownRefresh(() = >{
        setPage(1)
        setType('refresh')})return [list, count, filter, createUseFilter(setPage, setType, setFilter)] // Expose the filter update method and current filter criteria
}
Copy the code

use

let searchInv = -1

function Index() {
    const [list , count, filter, useActionFilter] = useGetList(getDevices, {search: ' '})
    return (
        <View className='news-manage padding-bottom20'>
            <View>
                <Input type='text'
                       placeholder='Please enter keywords'
                       onInput={(e)= > {
                           clearTimeout(searchInv)
                           searchInv = setTimeout(()=> {
                               console.log('e',e.detail.value)
                               useActionFilter({search: e.detail.value})
                           }, 300)
                       }}
                />
            </View>
           <List length={list ? list.length : null}
                 count={count}>
               <View className='marginX20 flex-wrap'>
                   {
                       list && list.length && list.map((device,index) => (
                           <DeviceCard key={device.name + index}
                                       device={device} />))}</View>
           </List>
        </View>)}Copy the code

Note: only one component can be defined in an Taro file


If you have any problem with the hook experience for the first time, please correct it.