實(shí)現(xiàn)一個(gè)上拉加載更多,要考慮一下幾個(gè)問題
1.什么時(shí)候觸發(fā)加載
2.什么時(shí)候不觸發(fā)
3.具體怎么觸發(fā)
根據(jù)以上的幾條,可以設(shè)計(jì)這樣一個(gè)組件
1.什么時(shí)候觸發(fā),即滾動(dòng)到什么位置時(shí)開始觸發(fā),此處就需要一個(gè)閾值進(jìn)行判斷,我們叫它threshold,
2.什么時(shí)候不觸發(fā),也許大家說只要不達(dá)到閾值時(shí)就不觸發(fā),其實(shí)這樣是有偏差的,為什么呢,首先,滾動(dòng)時(shí),假如它的閾值設(shè)為50,那么小于等于50時(shí),就會(huì)觸發(fā),此時(shí)假如我們?cè)?-50之間隨意更改值,那么就會(huì)導(dǎo)致一直觸發(fā),這顯然不是我們想要的,一般不觸發(fā)可以這么來判斷,是否在加載數(shù)據(jù),是否已經(jīng)加載完所有的數(shù)據(jù),所以,我們需要兩個(gè)屬性去判斷isFetching,hasMore
3.怎么去觸發(fā),此時(shí)我們需要一個(gè)去觸發(fā)的action,這個(gè)action每次執(zhí)行之后,都會(huì)把pageIndex加1
總結(jié)一下,這個(gè)組件,我們需要一下幾個(gè)props
1.threshold;2.isFetching;3.hasMore;4.action
好了,有了以上幾條,接下來實(shí)操部分,首先,我們?cè)趺慈ニ愠鲈趺磘hreshold
getBoundingClientRect
此處我是用的getBoundingClientRect,這個(gè)方法在area中也用到了,我們來看看它的一些有用的值,left,right,top,bottom,width,height
1.left指元素的左邊距可視區(qū)域左邊的距離
2.right指元素的右邊距可視區(qū)域左邊的距離
3.top指元素的頂部距可視區(qū)域頂部的距離
4.bottom指元素的底部距可視區(qū)域頂部的距離
盜個(gè)圖,一目了然

然后我們只要每次去計(jì)算當(dāng)前列表的底部距離減去可視區(qū)域的高度小于我們的閾值時(shí),即觸發(fā)加載,其實(shí),講到這里,核心已經(jīng)差不多了,接下來看代碼吧
import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import styles from './main.scss'
export default class Infinity extends PureComponent {
state = {
screenHeight: 0
}
render() {
const { hasMore } = this.props
return (
<div>
{this.props.children}
<p className={styles.infinity}>{hasMore ? '加載中...' : '沒有更多了'}</p>
</div>
)
}
componentDidMount() {
if (!this.props.children) {
console.error('You must add a child!')
return
} else if (Object.prototype.toString.call(this.props.children) == '[object Array]' && this.props.children.length > 0) {
console.error('Too many child')
return
}
this.setState({
screenHeight: window.innerHeight
})
window.addEventListener('scroll', this.scroll)
this.pagination()
}
componentWillUnmount() {
window.removeListener('scroll', this.scroll)
}
scroll = () => {
const { panel, threshold } = this.props
var rect = ReactDOM.findDOMNode(this).parentNode.getBoundingClientRect()
let value = rect.bottom - this.state.screenHeight
if (value < threshold) {
this.pagination()
}
}
pagination() {
const { action, count, total, isFetching, hasMore } = this.props
if (!isFetching && hasMore) {
console.log('加載中')
action()
}
}
}
Infinity.propTypes = {
action: PropTypes.func, // 具體加載下一頁(yè)的事件
threshold: PropTypes.number, // 加載的閾值
isFetching: PropTypes.bool,
hasMore: PropTypes.bool
}
Infinity.defaultProps = {
action: () => {},
threshold: 100,
isFetching: false,
hasMore: true
}
reducer中的處理
state = Immutable.update(state, 'dataList', (dataList, payload) => dataList.concat(payload), action.payload)
if (action.payload.length < state.pageSize) {
state = Immutable.merge(state, { hasMore: false })
}
return Immutable.update(state, 'pageIndex', (pageIndex, step) => pageIndex + step, 1)