上下文API值在钩子的useEffect中重置得太晚了



我有一个FilterContext提供程序和钩子useFilter在filtersContext.js:

import React, { useState, useEffect, useCallback } from 'react'
const FiltersContext = React.createContext({})
function FiltersProvider({ children }) {
const [filters, setFilters] = useState({})
return (
<FiltersContext.Provider
value={{
filters,
setFilters,
}}
>
{children}
</FiltersContext.Provider>
)
}

function useFilters(setPage) {
const context = React.useContext(FiltersContext)
if (context === undefined) {
throw new Error('useFilters must be used within a FiltersProvider')
}
const {
filters,
setFilters
} = context
useEffect(() => {
return () => {
console.log('reset the filters to an empty object')
setFilters({})
}
}, [setFilters])
{... do some additional stuff with filters if needed... not relevant }
return {
...context,
filtersForQuery: {
...filters
}
}
}
export { FiltersProvider, useFilters }

App.js使用Provider作为:

import React from 'react'
import { FiltersProvider } from '../filtersContext'

const App = React.memo(
({ children }) => {
...
...
return (
...
<FiltersProvider>
<RightSide flex={1} flexDirection={'column'}>
<Box flex={1}>
{children}
</Box>
</RightSide>
</FiltersProvider>
...
)
}
)
export default App

也就是说,FiltersProvider中的所有内容都成为过滤器的上下文。

现在出现问题描述:我在一页(Page1)上选择了过滤器,但是当我必须切换到另一页(Page2)时,我需要冲洗过滤器。这是在useEffect中使用return卸载的useFilters钩子中完成的。

问题是在新页面(Page2)中,在第一次渲染期间,我仍然获得过滤器的旧值,然后GraphQL请求在此之后发送。之后,钩子卸载发生,新页面(Page2)的第二次渲染发生,设置为空对象过滤器。

如果有人遇到类似的问题并解决了它?第一Page1.js:

const Page1 = () => {
....
const { filtersForQuery } = useFilters()

const { loading, error, data } = useQuery(GET_THINGS, {
variables: {
filter: filtersForQuery
}
})
....
}

第二Page2.js:

const Page2 = () => {
....
const { filtersForQuery } = useFilters()

console.log('page 2')
const { loading, error, data } = useQuery(GET_THINGS, {
variables: {
filter: filtersForQuery
}
})
....
}

从第1页点击到第2页的打印输出:

1. filters {isActive: {id: true}}
2. filters {isActive: {id: true}}
3. page 2
4. reset the filters to an empty object
5. 2 reset the filters to an empty object
6. filters {}
7. page 2

正如我在评论中提到的,它可能与缓存有关,我假设您使用的是GraphQL Apollo之类的东西。它有一个禁用查询缓存的选项:

fetchPolicy: "no-cache",
顺便说一下,如果你想,你也可以在Page Two组件中执行重置过程:
const PageTwo = () => {
const context = useFilters();
useEffect(() => {
context.setFilters({});
}, [context]);

苦苦挣扎的人:

import React, { useState, useEffect, useCallback, **useRef** } from 'react'
const FiltersContext = React.createContext({})
function FiltersProvider({ children }) {
const [filters, setFilters] = useState({})
return (
<FiltersContext.Provider
value={{
filters,
setFilters,
}}
>
{children}
</FiltersContext.Provider>
)
}

function useFilters(setPage) {
const isInitialRender = useRef(true)
const context = React.useContext(FiltersContext)
if (context === undefined) {
throw new Error('useFilters must be used within a FiltersProvider')
}
const {
filters,
setFilters
} = context
useEffect(() => {
**isInitialRender.current = false**
return () => {
console.log('reset the filters to an empty object')
setFilters({})
}
}, [setFilters])
{... do some additional stuff with filters if needed... not relevant }
return {
...context,
filtersForQuery: { // <---- here the filtersForQuery is another variable than just filters. This I have omitted in the question. I will modify it. 
**...(isInitialRender.current ? {} : filters)**
}
}
}
export { FiltersProvider, useFilters }

这里做的是:设置useRef bool变量并将其设置为true,只要它是true就总是返回一个空对象,当第一次渲染发生和/或setFilters函数更新时,设置isInitialRender。电流为假。这样我们就可以用钩子返回更新过的(非空的)过滤器对象。

最新更新