index.jsx 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import React, { useEffect, useRef, useState, useImperativeHandle, useMemo } from 'react';
  2. import Spin3 from '@/components/Spin/Spin3';
  3. import { ScrollView } from '@tarojs/components';
  4. import Taro from '@tarojs/taro';
  5. import { random } from '@/utils';
  6. export default React.forwardRef((props, ref) => {
  7. const {
  8. render,
  9. request,
  10. params = {},
  11. pageSize = 10,
  12. onError,
  13. onDataChange,
  14. noData,
  15. className,
  16. refres,//刷新复位
  17. refresherEnabled,
  18. ...leftProps
  19. } = props
  20. const [loading, setLoading] = useState(false)
  21. const contextRef = useRef()
  22. const [forceUpdate, setForceUpdate] = useState(0)
  23. const [list, setList] = useState([])
  24. const pageRef = useRef({ current: 1 })
  25. const [hasMore, setHasMore] = useState(false)
  26. const uqCls = useMemo(() => random('f'), [])
  27. // 滚动
  28. const handleScrollToLower = (e) => {
  29. if (!loading && hasMore) {
  30. pageRef.current.current += 1
  31. setForceUpdate(forceUpdate + 1)
  32. }
  33. }
  34. const loadingOff = () => {
  35. refres()
  36. }
  37. const fetchList = () => {
  38. if (!request) return;
  39. setLoading(true)
  40. request({
  41. ...params,
  42. pageSize,
  43. pageNum: pageRef.current.current
  44. }).then((res) => {
  45. const { records, ...pageInfo } = res || {}
  46. const lst = pageInfo.current === 1 ? records || [] : list.concat(records || [])
  47. setList(lst)
  48. setHasMore(pageInfo.current < pageInfo.pages)
  49. if (onDataChange) {
  50. onDataChange(lst, { paramsChanged: pageInfo.current === 1 })
  51. }
  52. pageRef.current = pageInfo
  53. setLoading(false)
  54. }).catch((err) => {
  55. console.error(err)
  56. setLoading(false)
  57. if (onError) {
  58. onError(err)
  59. }
  60. })
  61. }
  62. const fetchRef = useRef()
  63. fetchRef.current = fetchList
  64. useEffect(() => {
  65. pageRef.current.current = 1
  66. setHasMore(false)
  67. }, [params])
  68. // 请求数据
  69. useEffect(() => {
  70. fetchRef.current()
  71. }, [params, forceUpdate])
  72. useEffect(() => {
  73. Taro.nextTick(() => {
  74. Taro.createSelectorQuery().select(`.${uqCls}`).node(function (res) {
  75. contextRef.current = res.node
  76. }).exec()
  77. })
  78. }, [])
  79. // https://developers.weixin.qq.com/miniprogram/dev/api/ui/scroll/ScrollViewContext.html
  80. // ScrollViewContext 透传给父组件
  81. //https://zh-hans.reactjs.org/docs/hooks-reference.html#useimperativehandle
  82. useImperativeHandle(ref, () => ({
  83. context: contextRef.current,
  84. }))
  85. return (
  86. <ScrollView
  87. {...leftProps}
  88. scrollY
  89. enhanced
  90. refresherEnabled={refresherEnabled}
  91. onRefresherrefresh={fetchRef.current = fetchList}
  92. onScrollToLower={handleScrollToLower}
  93. className={`${className} ${uqCls} list-view`}
  94. >
  95. <view>
  96. {!render
  97. ? props.children
  98. : list.map((item, index) => render({ item, index }))
  99. }
  100. {!list || !list.length && noData}
  101. <Spin3 show={loading} />
  102. {list && list.length > 0 && !hasMore &&
  103. <view className='botton'>这是我的底线</view>
  104. }
  105. </view>
  106. </ScrollView>
  107. )
  108. })