taro3.x: 父元件傳子元件,元件之間相互更新問題
阿新 • • 發佈:2020-10-22
父元件呼叫子元件方法:實現父元件滾動下拉更新分頁
子元件註冊方法傳給父元件:
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)
圖例: