taro3.x: 父组件传子组件,组件之间相互更新问题

父组件调用子组件方法:实现父组件滚动下拉更新分页

子组件注册方法传给父组件:

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)

图例:

 

posted @ 2020-10-22 18:01  Nyan  阅读(542)  评论(0编辑  收藏  举报