首页 > 解决方案 > 使用自定义钩子我无法刷新/重新渲染组件

问题描述

我正在使用创建 LOAD MORE 功能的自定义钩子:

import React from 'react'

export const useLoadMore = (data, postsPerPage = 12) => {
  const [postsToShow, setPostsToShow] = React.useState([])
  const [next, setNext] = React.useState(postsPerPage)

  const loopWithSlice = (start, end) => {
    const slicedPosts = data.slice(start, end)
    setPostsToShow([...postsToShow, ...slicedPosts])
  }

  React.useEffect(() => {
    loopWithSlice(0, postsPerPage)
  }, [])

  const handleShowMorePosts = () => {
    loopWithSlice(next, next + postsPerPage)
    setNext(next + postsPerPage)
  }

  return { handleShowMorePosts, postsToShow }
}

然后我需要按价格过滤数组,当设置过滤器时,组件应该重新渲染但它没有这样做:

const Comp = ({ data }) => {

    const [filterBy, setFilter] = useState(null)
    const [defaultData, setData] = useState(get(data, 'products', []))
    
    const handleFilters = () => {
        let sorted = defaultData
    
        if (filterBy === 'high') {
          sorted = defaultData.sort(({ variants: [firstVariant] }, { variants: [secondVariant] }) => {
            return parseFloat(secondVariant.price) - parseFloat(firstVariant.price)
          })
        }
    
        return sorted
    }
    
    const { handleShowMorePosts, postsToShow } = useLoadMore(defaultData)
    
    useEffect(() => {
      setData(handleFilters())
    }, [filterBy, defaultData])
    
    return (<div>{postsToShow.map(...)}</div>)

}

handleFilters函数返回我需要{price: "1250.00"}的更高价格的输出。

我已经尝试了一些不同的方法,即使我在浏览器控制台中看到日志,它似乎也不起作用,组件没有重新渲染。

似乎useLoadMore钩子没有设置新的数据数组,它只抓取数组的初始值并设置它,但它在更改时没有设置新数组。

有任何想法吗?

标签: javascriptreactjsecmascript-6

解决方案


useEffect无法检测到数组更改,因此一种方法是array.length用作依赖项

 React.useEffect(() => {
    loopWithSlice(0, postsPerPage, true)
    setNext(postsPerPage)

  }, [data.length])

但它是不可靠的,好像下一个过滤的数据将具有相同的长度,它将不起作用。

更好的是我建议添加另一个参数useLoadMoreuseLoadMore = (data, postsPerPage = 12, shouldReset) 并根据它更多地重置负载

 React.useEffect(() => {
    loopWithSlice(0, postsPerPage, true)
    setNext(postsPerPage)

  }, [shouldReset])

并使用按值过滤作为其参数

 const { handleShowMorePosts, postsToShow } = useLoadMore(defaultData, 12, filterBy)

JSON.stringify(data)作为依赖应该工作。

 React.useEffect(() => {
    loopWithSlice(0, postsPerPage, true)
    setNext(postsPerPage)

  }, [JSON.stringify(data)])

如果是初始调用,则防止合并

  const loopWithSlice = (start, end, shouldReset) => {
    const slicedPosts = data.slice(start, end)
    if(shouldReset) {
      setPostsToShow(slicedPosts)
     } else {
      setPostsToShow([...postsToShow, ...slicedPosts])
    }

推荐阅读