• 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)

    图例:

  • 相关阅读:
    Apache虚拟主机配置(多个域名访问多个目录)(转)
    What I Learned as a Junior Developer Writing Tests for Legacy Code(转载)
    java.text包
    高性能前端框架React详解
    vue.js快速搭建图书管理平台
    vue.js用法和特性详解
    最接近原生APP体验的高性能前端框架——MUI
    用JS制作一个信息管理平台完整版
    JQuery实用技巧--学会你也是大神(1)——插件的制作技巧
    用JS制作一个信息管理平台(1)
  • 原文地址:https://www.cnblogs.com/Nyan-Workflow-FC/p/13859837.html
Copyright © 2020-2023  润新知