• taro3.x: 父组件调用子组件方法,相互更新优化(案例集)


    使用方法:

    useRef && useImperativeHandle && forwardRef
    lodash -> isEqual

    父组件:

    import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
    import { View, Input, ScrollView } 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'
    import { INewsParam } from '@constants/common'
    
    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,
            module_id: 1
          }
        }, { loading: false }).then((result: any) => {
          setNavData(result)
          setCurrentNav(result[0])
        })
      }, [])
    
      const handleNavClick = (item: any) => {
        setCurrentNav(item)
        setSearchTitle('')
        ref.current.onParamChange && ref.current.onParamChange(item.type)
      }
    
      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 handleScrollToLower = useCallback(() => {
        ref.current.onScorllToLower && ref.current.onScorllToLower()
      }, [])
    
      const handleInputBlur = (e: any) => {
        setSearchTitle(e.detail.value)
        ref.current.onParamChange && ref.current.onParamChange(currentNav.type, e.detail.value)
      }
    
      const toTop = () => {
        setScroll({
          top: Math.random(),
          fixed: false,
          style: {}
        })
      }
    
      const INIT_NEWS_PARAM: INewsParam = {
        type: currentNav.type,
        title: '',
        currentPage: 1,
      }
    
      const module_config = useMemo(() => {
        return {
          'image': <Photos {...INIT_NEWS_PARAM} ref={ref} />,
          'video': <Videos {...INIT_NEWS_PARAM} ref={ref} />,
          'article': <Articles {...INIT_NEWS_PARAM} ref={ref} />
        }
      }, [currentNav.type])
    
      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={handleInputBlur} value={searchTitle}></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.type === item.type && 'actived')}>
                      <View className="name">{item.title}</View>
                    </View>
                  ))
                }
              </ScrollView>
            </View>
            <View className="content">
              {module_config[currentNav.module]}
            </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, useRef, useState } from 'react'
    import Taro from '@tarojs/taro'
    import { View, Image, Text } from '@tarojs/components'
    import isEqual from 'lodash/isEqual'
    
    import api from '@services/api'
    import app from '@services/request'
    import { getTotalPage, INIT_PAGE, IPage } from '@utils/page'
    import { INewsParam } from '@constants/common'
    import './index.scss'
    
    
    const Photos = (props: INewsParam, ref: any) => {
        const PAGE_LIMIT = 10
        const [page, setPage] = useState<IPage>(INIT_PAGE)
        const [param, setParam] = useState<INewsParam>(props)
        const [loading, setLoading] = useState<boolean>(false)
        const [showEmpty, setShowEmpty] = useState<boolean>(false)
        const [photos, setPhotos] = useState<any[]>([])
        const paramRef = useRef<any>({})
    
        useEffect(() => {
            if (isEqual(paramRef.current, param)) {
                return
            }
            paramRef.current = param
            app.request({
                url: app.apiUrl(api.newsList),
                data: {
                    page: param.currentPage,
                    limit: PAGE_LIMIT,
                    type: param.type,
                    title: param.title
                }
            }, { loading: false }).then((result: any) => {
                setLoading(false)
                const totalPage = getTotalPage(PAGE_LIMIT, result.pagination.totalCount)
                setShowEmpty(totalPage <= props.currentPage)
                setPage({
                    totalCount: result.pagination.totalCount,
                    totalPage
                })
    
                if (param.currentPage === 1) {
                    setPhotos(result.data)
                } else {
                    setPhotos([...photos, ...result.data])
                }
            })
        }, [param])
    
        useImperativeHandle(ref, () => ({
            onScorllToLower: handleScrollToLower,
            onParamChange: handleParamChange
        }), [page.totalPage, param.currentPage])
    
        const handleParamChange = (type: string, title: string = '') => {
            setParam({
                type,
                title,
                currentPage: props.currentPage
            })
        }
    
        const handleScrollToLower = useCallback(() => {
            if (page.totalPage > param.currentPage) {
                setLoading(true)
                setParam({
                    ...param,
                    currentPage: param.currentPage + 1
                })
            } else {
                setShowEmpty(true)
            }
        }, [page.totalPage, param.currentPage])
    
        const toPhotoList = useCallback((item: any) => {
            Taro.navigateTo({
                url: `/pages/photo/index?id=${item.id}&title=${item.title}&subtitle=${item.sub_title}`
            })
        }, [])
    
        return (
            <View className="photos">
                {
                    photos.map((item: any, index: number) => (
                        <View key={index} className="item" onClick={() => toPhotoList(item)}>
                            <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 React.memo(forwardRef(Photos))
  • 相关阅读:
    nested exception is java.lang.IllegalStateException: No persistence units parsed from {classpath*:META-INF/persistence.xml}
    Thrift Expected protocol id ffffff82 but got 0
    idea
    Activity工作流入门之HelloWorld
    Thrift 入门之helloWorld
    Thrift入门之mac下的安装流程
    netty的解码器与粘包和拆包
    java反射(一)
    使用Spring报错:No default constructor found;
    jpa关联映射(一)
  • 原文地址:https://www.cnblogs.com/Nyan-Workflow-FC/p/13868087.html
Copyright © 2020-2023  润新知