父组件调用子组件方法:实现父组件滚动下拉更新分页
子组件注册方法传给父组件:
useImperativeHandle(ref, () => ({ innerFn: handleScrollToLower }), [page.totalPage, param.currentPage]) const handleScrollToLower = useCallback(() => { if (page.totalPage > param.currentPage) { setLoading(true) setParam({ currentPage: param.currentPage + 1 }) } else { setShowEmpty(true) } }, [page.totalPage, param.currentPage])
使用useImperativeHandle往ref注册handleScrollToLower方法传入父组件进行接收
const ref = useRef<any>({}) const handleScrollToLower = useCallback(() => { ref.current.innerFn && ref.current.innerFn() }, []) const getPhotoRender = useMemo(() => ( <Photos type="4" title={searchTitle} ref={ref} /> ), [searchTitle])
使用useMemo依赖更新子组件
const getPhotoRender = useMemo(() => ( <Photos type="4" title={searchTitle} ref={ref} /> ), [searchTitle])
父组件Index:
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { View, Input, ScrollView, Text } from '@tarojs/components' import classnames from 'classnames' import app from '@services/request' import api from '@services/api' import NavBar from '@components/navbar' import useNavData from '@hooks/useNavData' import Photos from '@components/photos' import Videos from '@components/videos' import Articles from '@components/articles' import './index.scss' const Index = () => { const { appHeaderHeight, contentHeight } = useNavData() const [searchTitle, setSearchTitle] = useState<string>('') const [scroll, setScroll] = useState<any>({}) const [navData, setNavData] = useState<any[]>([]) const [currentNav, setCurrentNav] = useState<any>({}) const ref = useRef<any>({}) useEffect(() => { app.request({ url: app.apiUrl(api.getNewsCate), data: { status: 1 } }, { loading: false }).then((result: any) => { setNavData(result) setCurrentNav(result[0]) }) }, []) const handleScroll = (e: any) => { const top = e.detail.scrollTop if (top > 200) { setScroll({ ...scroll, fixed: true, style: { top: appHeaderHeight } }) } if (top <= 200 && scroll.fixed) { setScroll({ ...scroll, fixed: false, style: {} }) } } const toTop = () => { setScroll({ top: Math.random(), fixed: false, style: {} }) } const handleNavClick = (item: any) => { setCurrentNav(item) } const handleScrollToLower = useCallback(() => { ref.current.innerFn && ref.current.innerFn() }, []) const handleInputChange = (e: any) => { console.log(e.detail) setSearchTitle(e.detail.value) } const getPhotoRender = useMemo(() => ( <Photos type="4" title={searchTitle} ref={ref} /> ), [searchTitle]) return ( <View className="index"> <NavBar /> <ScrollView scrollY style={{ maxHeight: contentHeight }} scrollWithAnimation scrollTop={scroll.top} onScroll={handleScroll} lowerThreshold={30} onScrollToLower={handleScrollToLower} > <View className="header"> <View className="logo"></View> <View className="title">案例集</View> </View> <View className="search"> <View className="search-content"> <View className="iconfont icon-search"></View> <Input className="search-input" placeholder="搜索" onBlur={handleInputChange}></Input> </View> </View> <View className={classnames('indexnav', scroll.fixed && 'fixed')} style={scroll.style}> <ScrollView scrollX> { navData.map((item: any, index: number) => ( <View key={index} onClick={() => handleNavClick(item)} className={classnames('indexnav-item', currentNav.id === item.id && 'actived')}> <View className="name">{item.title}</View> </View> )) } </ScrollView> </View> <View className="content"> {currentNav.type === '4' && getPhotoRender} {currentNav.type === '5' && <Videos />} {currentNav.type === '3' && <Articles />} </View> </ScrollView> <View className="action"> { scroll.fixed && <View className="action-item" onClick={toTop}> <View className="item-icon"> <View>TOP</View> </View> </View> } <View className="action-item"> <View className="item-icon"> <View className="iconfont icon-telephone-out"></View> </View> <View className="item-text"> <Text>联系我们</Text> </View> </View> </View> </View> ) } export default Index
子组件:
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from 'react' import Taro from '@tarojs/taro' import { View, Image, Text } from '@tarojs/components' import app from '@services/request' import api from '@services/api' import { getTotalPage, INIT_PAGE, IPage } from '@utils/page' import './index.scss' interface IParam { currentPage: number } const INIT_PARAM: IParam = { currentPage: 1 } interface IProps { type: string, title?: string } const Photos = (props: IProps, ref: any) => { const PAGE_LIMIT = 10 const [param, setParam] = useState<IParam>(INIT_PARAM) const [page, setPage] = useState<IPage>(INIT_PAGE) const [loading, setLoading] = useState<boolean>(false) const [showEmpty, setShowEmpty] = useState<boolean>(false) const [photos, setPhotos] = useState<any[]>([]) useEffect(() => { app.request({ url: app.apiUrl(api.newsList), data: { page: param.currentPage, limit: PAGE_LIMIT, type: props.type, title: props.title } }, { loading: false }).then((result: any) => { setLoading(false) const totalPage = getTotalPage(PAGE_LIMIT, result.pagination.totalCount) setShowEmpty(totalPage <= INIT_PARAM.currentPage) setPage({ totalCount: result.pagination.totalCount, totalPage }) if (param.currentPage === 1) { setPhotos(result.data) } else { setPhotos([...photos, ...result.data]) } }) }, [param.currentPage, props.title]) useImperativeHandle(ref, () => ({ innerFn: handleScrollToLower }), [page.totalPage, param.currentPage]) const handleScrollToLower = useCallback(() => { if (page.totalPage > param.currentPage) { setLoading(true) setParam({ currentPage: param.currentPage + 1 }) } else { setShowEmpty(true) } }, [page.totalPage, param.currentPage]) const toPhotoList = useCallback((id: string) => { Taro.navigateTo({ url: `/pages/photo/index?id=${id}` }) }, []) return ( <View className="photos"> { photos.map((item: any, index: number) => ( <View key={index} className="item" onClick={() => toPhotoList(item.id)}> <View className="item-photo"> <Image src={item.image_path}></Image> </View> <View className="item-text"> <View className="title">{item.title}</View> <View className="sub-title">{item.sub_title}</View> </View> <View className="item-mask"></View> </View> )) } { loading && <View className="empty-container"> <Text>正在加载中...</Text> </View> } { showEmpty && <View className="empty-container"> <Text>没有更多数据了</Text> </View> } </View> ) } export default forwardRef(Photos)
图例: