入门级react版scroll组件开发
什么是scroll组件?
一句话来说就是,能够在固定高度里进行滚动展示每个项目的组件
功能:滚动到底部加载更多、错误提示、没有更多、没有更多数据底部提示
技术栈
react + react hooks + fetch
开发
第一步先把基础组件写好
index.js
function Index(props) {
return (
<div className={'box-container'}>
<scroll>
</scroll>
</div>
)
}
scroll.js
function Scroll(props) {
return (
<ul className={'scroll-container'}>
2131
</ul>
)
}
item.js
function Item(props) {
return (
<div className={'item-container'}>
// 这里是为了渲染item也就是子组件
{
props.children instanceof Array ? props.children.map(item => item) : props.children
}
</div>
);
}
第二步开始渲染列表数据
index.js
const [list, setList] = useState([])
const [totalCount, setTotalCount] = useState(0)
const [listQuery, setListQuery] = useState({
page: 1,
rows: 10
})
// 依赖 listQuery 数据, 如果分页参数page改变,需要重新发送请求新的数据
useEffect(() => {
fetchData(listQuery).then(res => {
console.log('listQuery change')
const {bookList, totalCount} = res.data
const result = [...list, ...bookList] // 合并之前的数据
setList(result)
setTotalCount(totalCount)
})
}, [listQuery]);
// 类似vue的computed,当list和totalCount改变的时候拿到计算后的值
const hasMore = useMemo(() => {
return list.length < totalCount
}, [list, totalCount])
return (
<div className={'box-container'}>
<Scroll
sourceData = {list}
renderItem = {item => (
<Item key = {item.key}>
/*
这里放置Item的内容,也可以将单个数据传到Item里进行渲染
<Item key = {item.key} item={item}></Item>
*/
<span>{item.title}</span>
</Item>
)}
hasMore = {hasMore}
>
</Scroll>
</div>
)
scroll.js
const { sourceData, renderItem, hasMore } = props
return (
<ul className={'scroll-container'}>
{
sourceData.map(renderItem)
}
</ul>
);
第三步开始判断是否滚动到底部
const handleScroll = () => {
// 没有更多的时候 滚动不需要计算高度加载更多。
if(!hasMore) {
return
}
const sr = scrollRef.current // scroll 最外层元素
const sh = sr.scrollHeight
const ch = sr.clientHeight
const st = sr.scrollTop
//
if(sh - (st + 10) <= ch) {
// 加载更多
}
}
第四步加载更多
index.js
const [loading, setLoading] = useState(false)
useEffect(() => {
+++ setLoading(true)
fetchPageData(listQuery).then(res => {
console.log('listQuery change')
const {bookList, totalCount} = res.data
const result = [...list, ...bookList]
// 滚动加载延迟时间
setTimeout(() => {
setList(result)
setTotalCount(totalCount)
+++ setLoading(false)
}, 2000)
})
}, [listQuery]);
return (
<div className={'box-container'}>
<Scroll
sourceData={list}
renderItem={(item, index) => (
<Item key={item.title}>
<span>{index}{index}</span>
</Item>
)}
load={() => {
// 将load事件传给scroll组件触发。
let num = listQuery.page + 1
let result = {...listQuery}
result.page = num
setListQuery(result)
}}
loading={loading}
hasMore={hasMore}
/>
</div>
);
scroll.js
const handleScroll = () => {
+++ if(loading) {
+++ return
+++ }
if(!hasMore) {
return
}
const sr = scrollRef.current
const sh = sr.scrollHeight
const ch = sr.clientHeight
const st = sr.scrollTop
if(sh - (st + 10) <= ch) {
+++ load()
}
}
// 判断是否展示loading图标
const showLoading = useMemo(() => hasMore && loading, [hasMore, loading]);
return (
<ul className={'scroll-container'} ref={scrollRef} onScroll={handleScroll}>
{
sourceData.map(renderItem)
}
// 可以自定义loading图标
{
showLoading && <div className={'loading'}>
loading...
</div>
}
</ul>
);
以上代码完成 滚动到底部加载更多、没有更多。
错误提示、没有更多数据底部提示功能在loading下面增加并加上判断即可,需要注意优先级。还可以在当加载超时时候增加重新加载按钮…
效果图
谢谢观看
利用近期所学react知识做的一个小组件,希望有什么不足的地方大家可以指出.