将多个useState状态值组合成另一个状态值

问题描述 投票:0回答:2

我创建了两个自定义挂钩

usePagination
useSearch
。它们处理分页和搜索的逻辑,并且仅公开当前页面和搜索查询的 getter/setter。

这是我在列表组件中使用它们的方法:

const List = () => {
  const [currentPage, setCurrentPage] = usePagination()
  const [searchQuery, setSearchQuery] = useSearch()

  const queryParams = useMemo(() => ({
    page: currentPage,
    search: searchQuery
  }), [currentPage, searchQuery])

  // Pass the `queryParams` to an API endpoint to load my list items.
}

当搜索查询发生变化时,我需要将当前页面重置为1。像这样:

useEffect(()=>{
  setCurrentPage(1)
}, [searchQuery, setCurrentPage])

当然,按照上面的逻辑,这会导致两次API调用。当搜索查询更改时一个,然后在重置当前页面值后立即另一个。

有没有办法将我的自定义挂钩

currentPage
searchQuery
中的两个值组合成组合状态,以便我可以同时更新页码和查询?换句话说,除了废弃我的个人钩子并为所有事情使用单一状态之外,我还能做些什么吗?

例如

const [queryState, setQueryState] = useState({
  currentPage: 1,
  searchQuery: ""
})
reactjs react-hooks
2个回答
3
投票

是的,你几乎做对了。你可以做这样的事情:

const [queryState, setQueryState] = useState({
  currentPage: 1,
  searchQuery: ""
})

setQueryState((previousState) => {
  // change the state
  return previousState;
})

您甚至可以将其包装到一个钩子中,该钩子采用初始状态并返回 getter 和修改后的 setter。类似于以下内容:

// hook body
const [queryState, setQueryState] = useState(initialState)

const modifiedSetter = (newValues) => {
 setQueryState((previousState) => {
    return {...previousState, ...newValues};
 })
}

return [queryState, modifiedSetter]

它的用法是:

const [queryState, updateQueryState] = useMyCustomHook({...someinitialState})

// Well, getter works the same: queryState.searchQuery

// but the setter goes like this

updateQueryState({searchQuery: 'whatever'});
// or
updateQueryState({searchQuery: 'whatever', currentPage: 1});

1
投票
  1. 您能解释一下为什么需要 setState/setCurrentPage 函数作为依赖项吗?

  2. 作为预期效果,每当 useState 值更改时,整个组件都会重新渲染,这就是您有两个 API 调用的原因,因为两个状态都会导致重新渲染。

解决方案:假设您只想在 searchQuery 更改时进行新的 API 调用,而不是在 currentPage 数据更改时进行新的 API 调用,React 提供了 useRef,您可以使用它来存储/更新数据,而无需重新渲染并进行昂贵的 API 调用。

示例(在您的 usePagination 挂钩中):

function usePagination() {
   const currentPage = useRef(0);
     
   //make API call...
   
   //if (currentPage.current === 0) {...}

   return currentPage
}

然后在列表中:

const List = () => {
  const currentPage = usePagination()
  
  useEffect(()=>{
     currentPage.current = 1
  }, [searchQuery])

  //...
}
© www.soinside.com 2019 - 2024. All rights reserved.