Я получаю список элементов для отображения на странице списка — назовем их Todos. Извлечение осуществляется с помощью специального хука реагирования, который кэширует ответ под ключом запроса ['todo-list']
. Когда я получаю список, я получаю все данные для каждого дела в ответе. Затем я визуализирую список, сопоставляя ответ с компонентом <Todo>
, передавая элемент в качестве реквизита.
Проблема, с которой я столкнулся, заключается в том, что эти элементы отображаются в нескольких разных местах, и в каждом месте используется другой ключ запроса. Итак, там, где у меня есть ['todo-list']
, у меня также есть ['my-todo-list']
, ['all-todo-list']
и т. д. Эти элементы Todo могут быть «завершены», что запускает вызов мутации на серверной части, но оптимистично обновляет (через setQueryData
) отдельный элемент, чтобы пользовательский интерфейс отражал изменения. немедленно, не дожидаясь разрешения мутации и повторной выборки запроса списка. Вносить такие оптимистичные обновления в несколько списков задач довольно сложно и кажется неэффективным.
Мой вопрос: имеет ли смысл использовать ответ любого запроса списка дел на setQueryData
для отдельных элементов? Например, setQueryData(['todo', todo.id], todo
). Тогда любые дочерние компоненты, которым необходимо визуализировать эти данные, смогут просто получить объект Todo из кеша реагирующих запросов, при этом в качестве реквизита будет передано только поле id
.
В любом случае это считается антипаттерном или плохой практикой?
Вот базовый пример запроса todo-list
:
// custom react-query hook
export const useTodos = () => {
const todoQuery = useQuery(
['todo-list'],
() => {
return fetchTodos()
}
)
// Set the todo data in the cache
const queryClient = useQueryClient()
todoQuery.data?.todos?.forEach((todo) => {
queryClient.setQueryData(['todo', todo.id], todo)
})
return todoQuery
}
Это очень простой пример использования компонента Todo
:
// Todo component
function Todo({id}) {
const {data, isLoading} = useTodoById(id)
if (isLoading) {
return <p>Loading...</p>
}
return (
<h1 className = "todo">{todo.title}</h1>
)
}
export default Todo
Также стоит отметить, что крючок useTodoById
также является настраиваемым хуком реагирования на запросы, который извлекает одно задание по его идентификатору — значение кэшируется под ключом запроса ['todo', todo.id]
. Есть набор staleTime
на 10 минут.
То, что вы предлагаете, вовсе не плохая практика, на самом деле она упоминается в блоге TkDodo (мантейнер реагирования на запросы). Вы можете сделать это на основе push или pull, оба имеют плюсы и минусы, которые описаны в блоге. Единственная плохая практика, которую я наблюдаю, - это ваши ключи запроса. Часто рекомендуется использовать такие вещи, как ['todos', 'lists']
и ['todos', 'detail', 1]
, чтобы вы могли воспользоваться invalidateQuery
частичным совпадением. Я бы порекомендовал проверить сообщение в блоге об эффективных ключах запроса
Конечно, если вы назвали свой queryKeys, как в примере, который я упоминаю, и вы хотите обновить список задач по идентификатору 1
после того, как вы сделали PATCH
или PUT
, вы можете вызвать invalidateQueries({queryKey: ['todos', 'detail', 1])
, что сделает недействительным только этот конкретный запрос, но если вы хотите сделать недействительными все запросы которые связаны с todos
, которые вы можете вызвать invalidateQueries({queryKey: 'todos'})
, и они должны совпадать со всеми ключами запроса, в массиве которых есть задачи. Это простое соглашение об именах клавиш, дополнительную информацию вы можете найти в блоге, на который я дал ссылку.
Понял, это имеет смысл. Спасибо! Итак, с помощью этого шаблона (будь то pull или push) мы устанавливаем данные для подробных ключей запроса - например. ['todos', 'detail', 1]
. Но как вы думаете, как лучше всего управлять устаревшим временем для этих элементов? Например, я получаю список и устанавливаю initialData
. Компоненты рендеринга используют ключ запроса детализации для получения initialData
. Но когда срок действия staleTime
истечет, вы получите новый запрос для каждого из предметов. Например, на странице со списком, содержащей сотни элементов, это кажется немного тяжелым. Такова природа этого или есть более эффективный способ управления кешем?
Удивительно, большое спасибо! Приятно слышать, что такой подход признается специалистом по сопровождению запросов. Можете ли вы объяснить упомянутое вами частичное совпадение
invalidateQuery
? Или ссылку на какие-то ресурсы, чтобы я мог немного покопаться? И спасибо за queryKeys, я посмотрю на них, добавлю еще несколько записей, где это необходимо.