React useEffect:对值更改做出反应以更新另一个也是依赖项的人

时间:2020-08-18 14:05:50

标签: javascript reactjs react-hooks use-effect

我有一个很大的分页表。 我想在URL查询参数中包含页面索引,以便能够通过共享URL共享表的特定页面。

我的问题是页面不是唯一的查询参数,所以我需要做的是在页面更改时:

  1. 检索当前查询参数
  2. 从旧版本和新页面创建新的查询参数
  3. 更新查询参数。

但是,更新查询参数是一个问题,因为查询参数是检索旧参数的函数的依赖项,而我陷入了此循环。

我首先尝试做这样的事情:

import query from 'qs'
import { useLocation, useHistory } from 'react-router-dom'

function Comp() {
  const [pageIndex, setPageIndex] = useState(0)

  // Updates the query params using the provided ones.
  const updateQueryParams = useCallback(
    (pageIndex) => {
      const oldSearch = query.parse(location.search, { ignoreQueryPrefix: true })
      const newSearch = { ...oldSearch, pageIndex }
      history.push({ pathname: location.pathname, search: query.stringify(newSearch) })
    },
    [location.search, location.pathname]
  )

  // Updates the query params when pageIndex changes.
  useEffect(() => updateQueryParams(pageIndex), [updateQueryParams, pageIndex])
}

但是更新查询参数会更新location.search,它是updateQueryParams回调的依赖项,并且会触发无限循环。

我试图利用useRef存储搜索和路径名,并手动对其进行更新,但是我一直无法提出可行的解决方案。

我的最后尝试是在自定义钩子中提取逻辑,以将问题分解成较小的部分(并且我将不得不在其他地方重用此逻辑)。

此挂钩的当前状态为:

import { useLocation, useHistory } from 'react-router-dom'
import { useRef, useCallback } from 'react'
import query from 'qs'

export default function useQueryParams<QueryParams extends query.ParsedQs>(): [
  QueryParams,
  (newSearch: QueryParams) => void
] {
  const location = useLocation()
  const history = useHistory()

  const search = useRef(query.parse(location.search, { ignoreQueryPrefix: true }) as QueryParams)
  const pathname = useRef(location.pathname)

  const setSearch = useCallback(
    (newSearch: QueryParams) => {
      history.push({ pathname: pathname.current, search: query.stringify(newSearch) })
      search.current = newSearch
    },
    [history, pathname]
  )

  return [search.current, setSearch]
}

但这不能解决我的问题。 尝试访问路由会触发无限循环,并且控制台中出现Warning: Maximum update depth exceeded错误。

1 个答案:

答案 0 :(得分:0)

问题是由我的路由的声明方式引起的。

解决方案是从此模式更新我的所有路线:

<Route path="/login" component={Login} />

到这个:

<Route path="/login">
    <Login />
</Route>